news 2026/6/23 21:00: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/22 13:40:08

中电金信:智能辅助审单方案让跨境金融审核又快又准

在跨境金融业务中&#xff0c;审单工作一直是一项重要但繁琐的任务。让银行工作人员为堆积如山的国际信用证、商业发票、海运提单等单据而头疼&#xff1f;传统人工审单不仅耗时耗力&#xff0c;还容易因规则复杂、经验依赖性强而出现疏漏&#xff0c;影响业务效率与风险控制。…

作者头像 李华
网站建设 2026/6/23 0:48:53

虚拟专用网络门户的恶意扫描激增40倍

最近&#xff0c;一场针对某虚拟专用网络V/P/N的全球性扫描狂潮悄然来袭。从2025年11月14日起&#xff0c;针对该V/P/N门户的恶意扫描在24小时内狂飙40倍。按照“大规模扫描先行&#xff0c;攻击随后而至”的网络安全铁律&#xff0c;再结合近两年Ivanti、Fortinet、Cisco等多家…

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

3D点云标注效率革命:从单帧耗时到批量产出的实战经验分享

3D点云标注效率革命&#xff1a;从单帧耗时到批量产出的实战经验分享 【免费下载链接】SUSTechPOINTS 3D Point Cloud Annotation Platform for Autonomous Driving 项目地址: https://gitcode.com/gh_mirrors/su/SUSTechPOINTS 在自动驾驶数据标注的实践中&#xff0c;…

作者头像 李华
网站建设 2026/6/23 20:30:59

颠覆传统Shell安全思维:构建零信任脚本架构的5大创新策略

颠覆传统Shell安全思维&#xff1a;构建零信任脚本架构的5大创新策略 【免费下载链接】styleguide Style guides for Google-originated open-source projects 项目地址: https://gitcode.com/gh_mirrors/styleguide4/styleguide 在云原生和微服务架构盛行的今天&#x…

作者头像 李华
网站建设 2026/6/23 19:01:09

基于 Faster RCNN 的工业储罐类型识别与定位_卫星遥感图像分析

1. 基于 Faster RCNN 的工业储罐类型识别与定位&#xff1a;卫星遥感图像分析 1.1. 引言 工业储罐是石油化工、能源储存等领域的重要基础设施&#xff0c;其类型识别与定位对于安全监控、资源管理和城市规划具有重要意义。传统的储罐识别方法主要依赖人工目视解译&#xff0c;效…

作者头像 李华
网站建设 2026/6/23 19:33:12

为什么 Edge 才是安卓排名第1的浏览器?

前段时间推荐了谷歌的移动端浏览器Chrome&#xff0c;好多人评论“确实干净&#xff0c;但是用起来确实不太方便”。不太方便的原因也很简单&#xff0c;你懂得。吐槽手机厂商自带的浏览器要要说国内安卓厂商的自带手机浏览器&#xff0c;我相信很多人都想吐槽。一个简单的搜索…

作者头像 李华