news 2026/6/11 0:17:35

C++ CRTP 替代虚函数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ CRTP 替代虚函数

基本原理:

CRTP(Curiously Recurring Template Pattern)是一种 C++ 编程设计模式,类似于 RAII、SFINAE、这些东西。

核心思想只有一个东西:

即派生类继承以自身为模板参数的基类模板,这样子呢,在 C++ 编译替换期间时,它可以知道模版类型信息的,所以,可以调用目标的成员函数。

不带虚函数(用途一):

#include <iostream> #include <vector> #include <cmath> #include <memory> #include <iomanip> #include <variant> // CRTP 基类模板,不继承任何虚基类,完全静态多态 template <typename Derived> class Shape { public: double area() const { return static_cast<const Derived*>(this)->calculateArea(); } double perimeter() const { return static_cast<const Derived*>(this)->calculatePerimeter(); } void printInfo() const { std::cout << std::fixed << std::setprecision(2) << "Area: " << area() << ", Perimeter: " << perimeter() << "\n"; } }; // 圆形 class Circle : public Shape<Circle> { double radius; public: Circle(double r) : radius(r) {} double calculateArea() const { return M_PI * radius * radius; } double calculatePerimeter() const { return 2 * M_PI * radius; } }; // 矩形 class Rectangle : public Shape<Rectangle> { double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} double calculateArea() const { return width * height; } double calculatePerimeter() const { return 2 * (width + height); } }; // 三角形 class Triangle : public Shape<Triangle> { double a, b, c; public: Triangle(double s1, double s2, double s3) : a(s1), b(s2), c(s3) {} double calculateArea() const { double s = (a + b + c) / 2; return std::sqrt(s * (s - a) * (s - b) * (s - c)); } double calculatePerimeter() const { return a + b + c; } }; // 使用 std::variant 存储不同类型的形状,实现类型安全的统一处理 using ShapeVariant = std::variant<Circle, Rectangle, Triangle>; // Visitor 用于调用 printInfo struct PrintVisitor { template<typename T> void operator()(const T& shape) const { shape.printInfo(); } }; int main() { // 创建形状对象并存储在 std::variant 向量中 std::vector<ShapeVariant> shapes; shapes.emplace_back(Circle(5.0)); shapes.emplace_back(Rectangle(4.0, 6.0)); shapes.emplace_back(Triangle(3.0, 4.0, 5.0)); std::cout << "使用 std::variant 和 Visitor 统一处理(无虚函数调用):\n"; for (const auto& shape : shapes) { std::visit(PrintVisitor{}, shape); } // 也可以使用 lambda 直接访问 std::cout << "\n使用 lambda 直接访问 area 和 perimeter:\n"; for (const auto& shape : shapes) { std::visit([](const auto& s) { std::cout << std::fixed << std::setprecision(2) << "Area: " << s.area() << ", Perimeter: " << s.perimeter() << "\n"; }, shape); } // 静态多态单独处理示例 std::cout << "\n静态多态单独处理:\n"; Circle circle(5.0); Rectangle rectangle(4.0, 6.0); Triangle triangle(3.0, 4.0, 5.0); circle.printInfo(); rectangle.printInfo(); triangle.printInfo(); return 0; }

以下是带基类虚函数(用途二):

C++ 17

#include <iostream> #include <vector> #include <cmath> #include <variant> #include <memory> #include <iomanip> // CRTP 基类模板 template <typename Derived> class Shape { public: double area() const { return static_cast<const Derived*>(this)->calculateArea(); } double perimeter() const { return static_cast<const Derived*>(this)->calculatePerimeter(); } void printInfo() const { std::cout << std::fixed << std::setprecision(2) << "Area: " << area() << ", Perimeter: " << perimeter() << "\n"; } }; // 圆形 class Circle : public Shape<Circle> { double radius; public: Circle(double r) : radius(r) {} double calculateArea() const { return M_PI * radius * radius; } double calculatePerimeter() const { return 2 * M_PI * radius; } }; // 矩形 class Rectangle : public Shape<Rectangle> { double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} double calculateArea() const { return width * height; } double calculatePerimeter() const { return 2 * (width + height); } }; // 三角形 class Triangle : public Shape<Triangle> { double a, b, c; public: Triangle(double s1, double s2, double s3) : a(s1), b(s2), c(s3) {} double calculateArea() const { double s = (a + b + c) / 2; return sqrt(s * (s - a) * (s - b) * (s - c)); } double calculatePerimeter() const { return a + b + c; } }; // 使用 std::variant 存储不同类型的形状 using ShapeVariant = std::variant<Circle, Rectangle, Triangle>; // 访问者类,用于调用 variant 中的对象的成员函数 class ShapeVisitor { public: void operator()(const Circle& c) const { std::cout << "Circle: "; c.printInfo(); } void operator()(const Rectangle& r) const { std::cout << "Rectangle: "; r.printInfo(); } void operator()(const Triangle& t) const { std::cout << "Triangle: "; t.printInfo(); } }; int main() { // 创建不同类型的图形对象 Circle circle(5.0); Rectangle rectangle(4.0, 6.0); Triangle triangle(3.0, 4.0, 5.0); std::cout << "单独处理每个形状:\n"; circle.printInfo(); rectangle.printInfo(); triangle.printInfo(); std::cout << "\n使用 std::variant 统一处理:\n"; // 创建 variant 的 vector std::vector<ShapeVariant> shapes; shapes.push_back(circle); shapes.push_back(rectangle); shapes.push_back(triangle); ShapeVisitor visitor; for (const auto& shape : shapes) { std::visit(visitor, shape); } std::cout << "\n使用 lambda 表达式处理 variant:\n"; for (const auto& shape : shapes) { std::visit([](const auto& s) { using T = std::decay_t<decltype(s)>; if constexpr (std::is_same_v<T, Circle>) { std::cout << "Circle: "; } else if constexpr (std::is_same_v<T, Rectangle>) { std::cout << "Rectangle: "; } else if constexpr (std::is_same_v<T, Triangle>) { std::cout << "Triangle: "; } s.printInfo(); }, shape); } return 0; }

C++ 11

#include <iostream> #include <vector> #include <cmath> #include <memory> #include <iomanip> // 非模板基类,用于类型擦除 class IShape { public: virtual double area() const = 0; virtual double perimeter() const = 0; virtual void printInfo() const = 0; virtual ~IShape() = default; }; // CRTP 基类模板 template <typename Derived> class Shape : public IShape { public: double area() const override { return static_cast<const Derived*>(this)->calculateArea(); } double perimeter() const override { return static_cast<const Derived*>(this)->calculatePerimeter(); } void printInfo() const override { std::cout << std::fixed << std::setprecision(2) << "Area: " << area() << ", Perimeter: " << perimeter() << "\n"; } }; // 圆形 class Circle : public Shape<Circle> { double radius; public: Circle(double r) : radius(r) {} double calculateArea() const { return M_PI * radius * radius; } double calculatePerimeter() const { return 2 * M_PI * radius; } }; // 矩形 class Rectangle : public Shape<Rectangle> { double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} double calculateArea() const { return width * height; } double calculatePerimeter() const { return 2 * (width + height); } }; // 三角形 class Triangle : public Shape<Triangle> { double a, b, c; public: Triangle(double s1, double s2, double s3) : a(s1), b(s2), c(s3) {} double calculateArea() const { double s = (a + b + c) / 2; return sqrt(s * (s - a) * (s - b) * (s - c)); } double calculatePerimeter() const { return a + b + c; } }; int main() { // 创建不同类型的图形对象 std::cout << "使用基类指针统一处理:\n"; // 使用基类指针的 vector std::vector<std::unique_ptr<IShape>> shapes; shapes.push_back(std::make_unique<Circle>(5.0)); shapes.push_back(std::make_unique<Rectangle>(4.0, 6.0)); shapes.push_back(std::make_unique<Triangle>(3.0, 4.0, 5.0)); for (const auto& shape : shapes) { shape->printInfo(); } // 单独处理每个形状(静态多态) std::cout << "\n使用静态多态单独处理:\n"; Circle circle(5.0); Rectangle rectangle(4.0, 6.0); Triangle triangle(3.0, 4.0, 5.0); circle.printInfo(); rectangle.printInfo(); triangle.printInfo(); return 0; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 12:50:53

每天一个网络知识:什么是 Underlay?

在现代网络中&#xff0c;“Overlay”和“Underlay”是一对经常成双出现的概念。前者强调逻辑网络、虚拟化网络&#xff1b;后者则是真实世界中的物理基础网络。随着云计算、SD-WAN、数据中心虚拟化的发展&#xff0c;理解 Underlay 对构建可靠、高性能的网络来说至关重要。Und…

作者头像 李华
网站建设 2026/6/10 12:52:40

每天一个网络知识:什么是 SD-WAN?

SD-WAN 全称 Software-Defined Wide Area Network&#xff08;软件定义广域网&#xff09;。 一句话定义&#xff1a; SD-WAN 是一种利用软件定义技术&#xff0c;通过互联网宽带、4G/5G、专线等多条链路&#xff0c;为企业构建高性能、可控、安全的广域网连接的新技术。或者更…

作者头像 李华
网站建设 2026/6/10 14:43:51

oracle误drop表,通过回收站恢复

1.查询测试数据条数 SQL> select count(*) from test;COUNT(*) ----------62.drop 测试表 SQL> drop table test ;Table dropped.3.通过工具查询到在回收站中存在4.恢复回收站中误删除表 FLASHBACK TABLE TEST TO BEFORE DROP;5.查询恢复结果 SQL> select count(*…

作者头像 李华
网站建设 2026/6/10 12:53:13

探索Solana HD钱包的Python实现

引言 在区块链和加密货币领域,钱包管理是开发者需要面对的一个核心问题。特别是对于Solana这样一个快速发展的生态系统,了解如何在Python中实现和管理HD钱包(Hierarchical Deterministic Wallets)显得尤为重要。本文将通过实际的代码示例,展示如何在Python中生成并使用So…

作者头像 李华
网站建设 2026/6/10 23:51:35

Qwen-Image:2025最强中文文本渲染AI图像模型

Qwen-Image&#xff1a;重新定义中文文本渲染的AI图像引擎 在当前AIGC浪潮中&#xff0c;一个长期被忽视却至关重要的问题浮出水面&#xff1a;如何让AI真正“读懂”并“写好”中文&#xff1f; 尽管全球已有多个顶尖文生图模型问世&#xff0c;但在处理包含复杂中文文本的视…

作者头像 李华
网站建设 2026/6/10 13:19:42

LLaMA-Factory三大加速技术实战指南

大模型微调的三大加速利器&#xff1a;如何用消费级显卡跑动7B/13B模型 在今天&#xff0c;如果你还在为“没有A100怎么微调大模型”而发愁&#xff0c;那可能是你还没真正掌握这一轮技术红利的核心玩法。 LLaMA-Factory 的出现&#xff0c;像是一把钥匙&#xff0c;打开了大模…

作者头像 李华