第15章 多态 多态的概念与原理 多态是面向对象编程的核心特性之一,它允许使用统一的接口处理不同类型的对象,实现”一个接口,多种实现”的设计理念。在专家级C++开发中,多态不仅是代码组织工具,更是性能优化和系统设计的关键技术。
多态的核心原理 接口与实现分离 :通过抽象接口定义行为,具体实现由派生类提供运行时绑定 :调用哪个具体实现由对象的实际类型决定,而非声明类型代码复用 :统一的接口使得代码可以处理不同类型的对象扩展性 :新的派生类可以无缝集成到现有系统中类型擦除 :通过基类指针或引用隐藏具体类型信息多态的类型 C++支持两种类型的多态:
编译时多态(静态多态) :在编译阶段确定调用哪个函数
函数重载 运算符重载 模板(函数模板、类模板、可变参数模板) constexpr if(C++17+) 概念(Concepts,C++20+) 运行时多态(动态多态) :在运行阶段确定调用哪个函数
多态的底层实现 虚函数表(vtable)深度分析 核心原理 :虚函数表是编译器为每个包含虚函数的类生成的静态数组,存储该类所有虚函数的地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Base {public : virtual void func1 () {} virtual void func2 () {} void func3 () {} int value; }; class Derived : public Base {public : void func1 () override {} virtual void func4 () {} int derivedValue; };
虚函数调用的汇编分析 核心步骤 :
从对象指针获取虚指针(vptr) 通过虚指针访问虚函数表(vtable) 根据函数偏移量获取函数地址 调用函数 1 2 3 4 5 6 7 8 9 Base* ptr = new Derived (); ptr->func1 ();
虚函数表的内存开销 核心分析 :
每个包含虚函数的类都有一个虚函数表 每个对象都有一个虚指针(通常8字节,64位系统) 虚函数表存储在只读数据段(.rodata) 内存使用计算 :
类开销:虚函数表大小 = 虚函数数量 * 指针大小 对象开销:每个对象增加一个虚指针的大小 多态的性能分析 虚函数调用vs普通函数调用 性能差异 :
普通函数调用:直接地址调用,开销极小 虚函数调用:需要多次内存访问(vptr -> vtable -> 函数地址),开销较大 基准测试 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 void benchmarkFunctionCalls () { Base* basePtr = new Derived (); Derived* derivedPtr = new Derived (); auto start = std::chrono::high_resolution_clock::now (); for (int i = 0 ; i < 10000000 ; ++i) { basePtr->func1 (); } auto end = std::chrono::high_resolution_clock::now (); std::cout << "Virtual calls: " << std::chrono::duration_cast <std::chrono::milliseconds>(end - start).count () << "ms" << std::endl; start = std::chrono::high_resolution_clock::now (); for (int i = 0 ; i < 10000000 ; ++i) { derivedPtr->func1 (); } end = std::chrono::high_resolution_clock::now (); std::cout << "Non-virtual calls: " << std::chrono::duration_cast <std::chrono::milliseconds>(end - start).count () << "ms" << std::endl; delete basePtr; delete derivedPtr; }
运行时多态的实现 虚函数 核心特性 :虚函数是在基类中声明并在派生类中重写的成员函数,通过虚函数表(vtable)实现运行时多态。
高级特性 :
虚函数的默认参数 :默认参数是静态绑定的,使用基类声明中的默认值虚函数与const限定符 :const和非const版本的成员函数可以重载,const属性是函数签名的一部分虚函数与引用 :多态同样适用于引用,引用的静态类型决定可访问的接口,动态类型决定实际调用的函数虚函数与final关键字 :使用final关键字防止虚函数被进一步重写1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 class Base {public : virtual void doSomething () { std::cout << "Base::doSomething()" << std::endl; } virtual void doSomethingWithDefault (int value = 10 ) { std::cout << "Base::doSomethingWithDefault() with value " << value << std::endl; } virtual void doSomethingConst () const { std::cout << "Base::doSomethingConst()" << std::endl; } virtual void doSomethingFinal () final { std::cout << "Base::doSomethingFinal()" << std::endl; } virtual ~Base () { std::cout << "Base::~Base()" << std::endl; } }; class Derived : public Base {public : void doSomething () override { std::cout << "Derived::doSomething()" << std::endl; Base::doSomething (); } void doSomethingWithDefault (int value = 20 ) override { std::cout << "Derived::doSomethingWithDefault() with value " << value << std::endl; } void doSomethingConst () const override { std::cout << "Derived::doSomethingConst()" << std::endl; } ~Derived () { std::cout << "Derived::~Derived()" << std::endl; } }; void usePolymorphism (Base* ptr) { ptr->doSomething (); ptr->doSomethingWithDefault (); ptr->doSomethingConst (); ptr->doSomethingFinal (); } int main () { Base* basePtr = new Base (); Base* derivedPtr = new Derived (); std::cout << "Calling on Base* pointing to Base:" << std::endl; usePolymorphism (basePtr); std::cout << "\nCalling on Base* pointing to Derived:" << std::endl; usePolymorphism (derivedPtr); delete basePtr; delete derivedPtr; return 0 ; }
纯虚函数与抽象类 核心特性 :纯虚函数是在基类中声明但不提供实现的虚函数,包含纯虚函数的类称为抽象类。
设计原则 :
接口分离原则 :接口应该小而专注,只包含必要的方法单一职责原则 :每个接口应该只负责一个功能领域依赖倒置原则 :高层模块应该依赖于抽象接口,而不是具体实现高级应用 :
混合接口和实现 :抽象类可以包含部分实现,减少派生类的代码重复模板方法模式 :通过抽象类定义算法骨架,派生类实现具体步骤策略模式 :通过接口定义算法家族,运行时选择具体实现1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 class AbstractShape {public : virtual ~AbstractShape () = default ; virtual void draw () const = 0 ; virtual double area () const = 0 ; virtual std::string name () const { return "AbstractShape" ; } void process () const { std::cout << "Processing " << name () << ":" << std::endl; draw (); std::cout << "Area: " << area () << std::endl; std::cout << "Processing completed." << std::endl; } }; class Circle : public AbstractShape {private : double radius; public : explicit Circle (double r) : radius(r) { } void draw () const override { std::cout << "Drawing a circle with radius " << radius << std::endl; } double area () const override { return M_PI * radius * radius; } std::string name () const override { return "Circle" ; } }; class Rectangle : public AbstractShape {private : double width, height; public : Rectangle (double w, double h) : width (w), height (h) {} void draw () const override { std::cout << "Drawing a rectangle with width " << width << " and height " << height << std::endl; } double area () const override { return width * height; } std::string name () const override { return "Rectangle" ; } }; void processShape (const AbstractShape& shape) { shape.process (); } std::unique_ptr<AbstractShape> createShape (const std::string& type, double ... args) { if (type == "circle" ) { return std::make_unique <Circle>(args[0 ]); } else if (type == "rectangle" ) { return std::make_unique <Rectangle>(args[0 ], args[1 ]); } else { throw std::invalid_argument ("Unknown shape type: " + type); } }
接口 核心特性 :接口是只包含纯虚函数的抽象类,用于定义行为契约。
现代C++接口设计 :
使用纯虚函数 :只定义方法签名,不提供实现虚析构函数 :确保派生类的析构函数被正确调用空基类优化 :接口类通常不包含成员变量,利用空基类优化减少内存开销多重继承 :接口可以多重继承,实现多个行为契约接口设计最佳实践 :
命名约定 :接口名称通常使用形容词形式(如Drawable、Colorable)方法数量 :每个接口应该只包含相关的方法,遵循单一职责原则参数设计 :使用值语义或const引用,避免不必要的指针返回类型 :使用具体类型或智能指针,避免原始指针1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 class Drawable {public : virtual ~Drawable () = default ; virtual void draw () const = 0 ; virtual void resize (double factor) = 0 ; }; class Colorable {public : virtual ~Colorable () = default ; virtual void setColor (const std::string& color) = 0 ; virtual std::string getColor () const = 0 ; }; class Serializable {public : virtual ~Serializable () = default ; virtual std::string serialize () const = 0 ; virtual void deserialize (const std::string& data) = 0 ; }; class ColoredCircle : public Drawable, public Colorable, public Serializable {private : double radius; std::string color; public : ColoredCircle (double r, std::string c) : radius (r), color (std::move (c)) {} void draw () const override { std::cout << "Drawing a " << color << " circle with radius " << radius << std::endl; } void resize (double factor) override { radius *= factor; } void setColor (const std::string& c) override { color = c; } std::string getColor () const override { return color; } std::string serialize () const override { return "{\"type\":\"circle\",\"radius\":\"" + std::to_string (radius) + "\",\"color\":\"" + color + "\"}" ; } void deserialize (const std::string& data) override { size_t radiusPos = data.find ("radius" ); size_t colorPos = data.find ("color" ); if (radiusPos != std::string::npos && colorPos != std::string::npos) { } } }; void useInterfaces () { ColoredCircle circle (5.0 , "red" ) ; Drawable& drawable = circle; drawable.draw (); drawable.resize (1.5 ); Colorable& colorable = circle; colorable.setColor ("blue" ); std::cout << "Color: " << colorable.getColor () << std::endl; Serializable& serializable = circle; std::string data = serializable.serialize (); std::cout << "Serialized: " << data << std::endl; std::vector<std::unique_ptr<Drawable>> drawables; drawables.push_back (std::make_unique <ColoredCircle>(3.0 , "green" )); for (const auto & item : drawables) { item->draw (); } }
编译时多态的实现 函数重载 核心特性 :函数重载允许在同一个作用域内定义多个同名函数,通过参数列表的不同来区分。
高级特性 :
名称修饰(Name Mangling) :编译器通过修饰函数名来区分重载函数,包含参数类型信息重载解析 :编译器根据实参类型、数量和顺序选择最匹配的函数隐式类型转换 :在重载解析中会考虑标准类型转换引用折叠 :在模板重载中处理引用类型的特殊规则1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Calculator {public : int add (int a, int b) { return a + b; } double add (double a, double b) { return a + b; } std::string add (const std::string& a, const std::string& b) { return a + b; } template <typename T> T add (const T& a, const T& b) { return a + b; } };
运算符重载 核心特性 :运算符重载允许为自定义类型定义运算符的行为。
高级应用 :
表达式模板 :用于优化复杂表达式的计算(如Eigen库)智能指针运算符 :重载*和->运算符实现指针语义迭代器运算符 :重载++, –, *, ->等实现容器遍历类型转换运算符 :实现自定义类型之间的隐式转换1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 class Vector2D {private : double x, y; public : Vector2D (double x = 0 , double y = 0 ) : x (x), y (y) {} Vector2D operator +(const Vector2D& other) const { return Vector2D (x + other.x, y + other.y); } Vector2D operator -(const Vector2D& other) const { return Vector2D (x - other.x, y - other.y); } Vector2D operator *(double scalar) const { return Vector2D (x * scalar, y * scalar); } Vector2D& operator +=(const Vector2D& other) { x += other.x; y += other.y; return *this ; } double & operator [](size_t index) { if (index == 0 ) return x; if (index == 1 ) return y; throw std::out_of_range ("Vector2D index out of range" ); } explicit operator bool () const { return x != 0.0 || y != 0.0 ; } friend std::ostream& operator <<(std::ostream& os, const Vector2D& vec) { os << "(" << vec.x << ", " << vec.y << ")" ; return os; } friend Vector2D operator *(double scalar, const Vector2D& vec) { return vec * scalar; } }; void useVector2D () { Vector2D v1 (1 , 2 ) ; Vector2D v2 (3 , 4 ) ; Vector2D v3 = v1 + v2; Vector2D v4 = v1 - v2; Vector2D v5 = v1 * 2.0 ; Vector2D v6 = 2.0 * v1; v1 += v2; std::cout << "v1: " << v1 << std::endl; std::cout << "v2: " << v2 << std::endl; std::cout << "v1 + v2: " << v3 << std::endl; std::cout << "v1 - v2: " << v4 << std::endl; std::cout << "v1 * 2: " << v5 << std::endl; std::cout << "2 * v1: " << v6 << std::endl; }
模板与静态多态 核心特性 :模板允许定义通用的函数或类,在编译时根据实际类型生成具体的代码。
高级模板技术 :
SFINAE(替换失败不是错误) :用于条件性启用模板重载模板特化 :为特定类型提供自定义实现部分特化 :为模板参数的子集提供特化可变参数模板 :处理任意数量的模板参数模板模板参数 :接受模板作为参数的模板1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 template <typename T> T maximum (T a, T b) { return a > b ? a : b; } template <> const char * maximum (const char * a, const char * b) { return std::strcmp (a, b) > 0 ? a : b; } template <typename ... Args> void print (Args&&... args) { (std::cout << ... << std::forward<Args>(args)) << std::endl; } template <typename T> class Stack {private : std::vector<T> elements; public : void push (const T& value) { elements.push_back (value); } T pop () { if (elements.empty ()) { throw std::runtime_error ("Stack is empty" ); } T value = elements.back (); elements.pop_back (); return value; } bool isEmpty () const { return elements.empty (); } template <typename U> void push_multiple (U&&... values) { (push (std::forward<U>(values)), ...); } }; void useTemplates () { int maxInt = maximum (10 , 20 ); double maxDouble = maximum (3.14 , 2.71 ); std::string maxString = maximum (std::string ("apple" ), std::string ("banana" )); const char * maxCString = maximum ("hello" , "world" ); Stack<int > intStack; intStack.push_multiple (1 , 2 , 3 , 4 , 5 ); while (!intStack.isEmpty ()) { std::cout << intStack.pop () << " " ; } std::cout << std::endl; Stack<std::string> stringStack; stringStack.push ("hello" ); stringStack.push ("world" ); while (!stringStack.isEmpty ()) { std::cout << stringStack.pop () << " " ; } std::cout << std::endl; print ("The maximum values are:" , maxInt, ", " , maxDouble, ", " , maxString); }
CRTP(奇异递归模板模式) 核心特性 :CRTP是一种静态多态技术,通过模板继承实现编译时多态,避免虚函数的运行时开销。
优势 :
零运行时开销:所有调用在编译时解析 内联友好:编译器可以更好地优化调用 类型安全:在编译时捕获类型错误 灵活性:可以在基类中访问派生类的成员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 template <typename Derived> class Base {public : void interface () { static_cast <Derived*>(this )->implementation (); } void commonFunction () { std::cout << "Common functionality from Base" << std::endl; } }; class Derived1 : public Base<Derived1> {public : void implementation () { std::cout << "Implementation from Derived1" << std::endl; } }; class Derived2 : public Base<Derived2> {public : void implementation () { std::cout << "Implementation from Derived2" << std::endl; } }; template <typename T> void useBase (Base<T>& obj) { obj.interface (); obj.commonFunction (); } template <typename Derived> class Counter {private : static inline size_t count = 0 ; public : Counter () { ++count; } ~Counter () { --count; } static size_t getCount () { return count; } Derived& derived () { return static_cast <Derived&>(*this ); } }; class MyClass : public Counter<MyClass> {public : void doSomething () { std::cout << "MyClass::doSomething()" << std::endl; } }; void useCRTP () { Derived1 d1; Derived2 d2; useBase (d1); useBase (d2); { MyClass obj1; MyClass obj2; std::cout << "MyClass count: " << MyClass::getCount () << std::endl; } std::cout << "MyClass count after scope: " << MyClass::getCount () << std::endl; }
现代C++概念(Concepts) 核心特性 :C++20引入的概念(Concepts)用于约束模板参数,提供更清晰的错误信息和更简洁的代码。
优势 :
更清晰的接口约束 更友好的编译错误信息 减少SFINAE的复杂性 提高代码可读性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 template <typename T> concept Arithmetic = std::is_arithmetic_v<T>; template <typename T> concept Printable = requires (T t) { { std::cout << t } -> std::same_as<std::ostream&>; }; template <typename T> concept Numeric = Arithmetic<T> && Printable<T>; template <Numeric T> T add (T a, T b) { return a + b; } template <typename T> concept Drawable = requires (T t) { { t.draw () } -> std::same_as<void >; }; template <Drawable Derived> class Shape {public : void render () { static_cast <Derived*>(this )->draw (); } }; class Circle : public Shape<Circle> {public : void draw () { std::cout << "Drawing a circle" << std::endl; } }; class Square : public Shape<Square> {public : void draw () { std::cout << "Drawing a square" << std::endl; } }; auto createShape () -> Shape<auto > { return Circle{}; } void useConcepts () { std::cout << add (1 , 2 ) << std::endl; std::cout << add (1.5 , 2.5 ) << std::endl; Circle circle; Square square; circle.render (); square.render (); }
多态的高级应用 虚函数与默认参数 核心原则 :虚函数的默认参数是静态绑定的,即使用基类声明中的默认参数值。
设计注意事项 :
避免在虚函数中使用默认参数,因为这会导致行为不一致 考虑使用函数重载或参数对象模式替代默认参数 如果必须使用默认参数,确保所有派生类使用相同的默认值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Base {public : virtual void doSomething (int value = 10 ) { std::cout << "Base::doSomething() with value " << value << std::endl; } void doSomething () { doSomething (10 ); } }; class Derived : public Base {public : void doSomething (int value = 20 ) override { std::cout << "Derived::doSomething() with value " << value << std::endl; } void doSomething () { doSomething (20 ); } }; void testDefaultArguments () { Base* basePtr = new Base (); Base* derivedPtr = new Derived (); basePtr->doSomething (); derivedPtr->doSomething (); basePtr->doSomething (); static_cast <Derived*>(derivedPtr)->doSomething (); delete basePtr; delete derivedPtr; }
虚函数与const限定符 核心特性 :const和非const版本的成员函数可以重载,虚函数的const属性是其签名的一部分。
高级应用 :
const正确性 :通过const重载实现对常量和非常量对象的不同处理线程安全 :const成员函数通常应该是线程安全的不可变性设计 :使用const成员函数表示不修改对象状态的操作1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 class Base {public : virtual void doSomething () { std::cout << "Base::doSomething() (non-const)" << std::endl; } virtual void doSomething () const { std::cout << "Base::doSomething() (const)" << std::endl; } virtual Base& getSelf () { return *this ; } virtual const Base& getSelf () const { return *this ; } }; class Derived : public Base {public : void doSomething () override { std::cout << "Derived::doSomething() (non-const)" << std::endl; } void doSomething () const override { std::cout << "Derived::doSomething() (const)" << std::endl; } Derived& getSelf () override { return *this ; } const Derived& getSelf () const override { return *this ; } }; void testConstPolymorphism () { Derived d; const Derived& constRef = d; d.doSomething (); constRef.doSomething (); Base* basePtr = new Derived (); const Base* constBasePtr = new Derived (); basePtr->doSomething (); constBasePtr->doSomething (); Base& baseRef = basePtr->getSelf (); const Base& constBaseRef = constBasePtr->getSelf (); delete basePtr; delete constBasePtr; }
虚函数与引用 核心特性 :多态同样适用于引用,引用的静态类型决定了可访问的接口,而动态类型决定了实际调用的函数。
高级应用 :
引用包装器 :使用std::reference_wrapper实现可复制的引用类型擦除 :通过引用实现运行时多态完美转发 :在模板中保持引用类型信息1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Base {public : virtual void doSomething () { std::cout << "Base::doSomething()" << std::endl; } virtual ~Base () = default ; }; class Derived : public Base {public : void doSomething () override { std::cout << "Derived::doSomething()" << std::endl; } void doSomethingElse () { std::cout << "Derived::doSomethingElse()" << std::endl; } }; void testReferenceWrapper () { Derived d1, d2; Base b; std::vector<std::reference_wrapper<Base>> objects = {b, d1, d2}; for (auto & obj : objects) { obj.get ().doSomething (); } } void testReferencePolymorphism () { Derived d; Base& baseRef = d; baseRef.doSomething (); Derived& derivedRef = static_cast <Derived&>(baseRef); derivedRef.doSomethingElse (); testReferenceWrapper (); }
类型擦除 核心特性 :类型擦除是一种技术,通过基类指针或引用隐藏具体类型信息,实现运行时多态。
高级实现 :
基于继承的类型擦除 :使用虚函数接口基于模板的类型擦除 :使用std::function等值语义类型擦除 :如std::any(C++17+)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 class AnyCallable {public : virtual ~AnyCallable () = default ; virtual void operator () () = 0 ; }; template <typename F> class CallableWrapper : public AnyCallable {private : F func; public : explicit CallableWrapper (F&& f) : func(std::forward<F>(f)) { } void operator () () override { func (); } }; class Event {private : std::vector<std::unique_ptr<AnyCallable>> handlers; public : template <typename F> void addHandler (F&& handler) { handlers.push_back (std::make_unique<CallableWrapper<F>>(std::forward<F>(handler))); } void trigger () { for (const auto & handler : handlers) { (*handler)(); } } }; void testTypeErasure () { Event event; event.addHandler ([]() { std::cout << "Lambda handler called" << std::endl; }); struct Handler { void operator () () { std::cout << "Functor handler called" << std::endl; } }; event.addHandler (Handler{}); void freeFunction () { std::cout << "Free function handler called" << std::endl; } event.addHandler (freeFunction); event.trigger (); std::any value = 42 ; std::cout << "std::any containing int: " << std::any_cast <int >(value) << std::endl; value = std::string ("hello" ); std::cout << "std::any containing string: " << std::any_cast <std::string>(value) << std::endl; }
硬件感知的多态设计 核心特性 :考虑硬件特性(如缓存、分支预测、SIMD)的多态设计,提高代码性能。
优化策略 :
缓存友好 :合理设计对象布局,减少缓存未命中分支预测 :减少虚函数调用的分支预测失败SIMD友好 :设计支持向量化的接口内存局部性 :提高数据和指令的局部性1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 class Shape {public : virtual ~Shape () = default ; virtual void draw () const = 0 ; virtual double area () const = 0 ; struct BoundingBox { double x, y, width, height; } boundingBox; protected : Shape (double x, double y, double width, double height) : boundingBox{x, y, width, height} {} }; class Circle : public Shape {private : double radius; public : Circle (double x, double y, double r) : Shape (x, y, r * 2 , r * 2 ), radius (r) {} void draw () const override { std::cout << "Drawing circle at (" << boundingBox.x << ", " << boundingBox.y << ") with radius " << radius << std::endl; } double area () const override { return M_PI * radius * radius; } }; class Rectangle : public Shape {public : Rectangle (double x, double y, double width, double height) : Shape (x, y, width, height) {} void draw () const override { std::cout << "Drawing rectangle at (" << boundingBox.x << ", " << boundingBox.y << ") with dimensions " << boundingBox.width << "x" << boundingBox.height << std::endl; } double area () const override { return boundingBox.width * boundingBox.height; } }; class SIMDProcessable {public : virtual ~SIMDProcessable () = default ; virtual void process (float * data, size_t size) = 0 ; virtual void processSIMD (float * data, size_t size) { process (data, size); } virtual bool supportsSIMD () const { return false ; } }; class SimpleProcessor : public SIMDProcessable {public : void process (float * data, size_t size) override { for (size_t i = 0 ; i < size; ++i) { data[i] = data[i] * 2.0f + 1.0f ; } } }; #ifdef __AVX2__ class AVX2Processor : public SIMDProcessable {public : void process (float * data, size_t size) override { for (size_t i = 0 ; i < size; ++i) { data[i] = data[i] * 2.0f + 1.0f ; } } void processSIMD (float * data, size_t size) override { size_t i = 0 ; for (; i + 7 < size; i += 8 ) { __m256 vec = _mm256_loadu_ps(&data[i]); vec = _mm256_mul_ps(vec, _mm256_set1_ps(2.0f )); vec = _mm256_add_ps(vec, _mm256_set1_ps(1.0f )); _mm256_storeu_ps(&data[i], vec); } for (; i < size; ++i) { data[i] = data[i] * 2.0f + 1.0f ; } } bool supportsSIMD () const override { return true ; } }; #endif void testHardwareAwarePolymorphism () { std::vector<std::unique_ptr<Shape>> shapes; shapes.push_back (std::make_unique <Circle>(0 , 0 , 5 )); shapes.push_back (std::make_unique <Rectangle>(10 , 10 , 20 , 30 )); shapes.push_back (std::make_unique <Circle>(40 , 40 , 10 )); for (const auto & shape : shapes) { shape->draw (); std::cout << "Area: " << shape->area () << std::endl; } std::vector<float > data (1024 ) ; std::generate (data.begin (), data.end (), []() { return static_cast <float >(rand ()) / RAND_MAX; }); std::unique_ptr<SIMDProcessable> processor; #ifdef __AVX2__ processor = std::make_unique <AVX2Processor>(); std::cout << "Using AVX2 processor" << std::endl; #else processor = std::make_unique <SimpleProcessor>(); std::cout << "Using simple processor" << std::endl; #endif if (processor->supportsSIMD ()) { processor->processSIMD (data.data (), data.size ()); } else { processor->process (data.data (), data.size ()); } std::cout << "Processed first 4 elements: " << data[0 ] << ", " << data[1 ] << ", " << data[2 ] << ", " << data[3 ] << std::endl; }
多态与继承层次 核心特性 :在复杂的继承层次中,多态允许通过基类指针或引用调用任何派生类的虚函数。
最佳实践 :
保持继承层次浅而宽,避免深层继承 优先使用组合而非继承 遵循里氏替换原则 合理使用接口隔离原则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 class Animal {public : virtual ~Animal () = default ; virtual void makeSound () const = 0 ; virtual void move () const = 0 ; virtual std::string name () const = 0 ; }; class Mammal : public Animal {public : void move () const override { std::cout << "Mammal moves by walking" << std::endl; } }; class Bird : public Animal {public : void move () const override { std::cout << "Bird moves by flying" << std::endl; } }; class Fish : public Animal {public : void move () const override { std::cout << "Fish moves by swimming" << std::endl; } }; class Dog : public Mammal {public : void makeSound () const override { std::cout << "Dog barks" << std::endl; } std::string name () const override { return "Dog" ; } }; class Cat : public Mammal {public : void makeSound () const override { std::cout << "Cat meows" << std::endl; } std::string name () const override { return "Cat" ; } }; class Eagle : public Bird {public : void makeSound () const override { std::cout << "Eagle screeches" << std::endl; } std::string name () const override { return "Eagle" ; } }; class Salmon : public Fish {public : void makeSound () const override { std::cout << "Salmon makes no sound" << std::endl; } std::string name () const override { return "Salmon" ; } }; void processAnimal (const Animal& animal) { std::cout << "Processing " << animal.name () << ":" << std::endl; animal.makeSound (); animal.move (); std::cout << std::endl; } class AnimalFactory {public : static std::unique_ptr<Animal> createAnimal (const std::string& type) { if (type == "dog" ) { return std::make_unique <Dog>(); } else if (type == "cat" ) { return std::make_unique <Cat>(); } else if (type == "eagle" ) { return std::make_unique <Eagle>(); } else if (type == "salmon" ) { return std::make_unique <Salmon>(); } else { throw std::invalid_argument ("Unknown animal type: " + type); } } }; void testAnimalPolymorphism () { Dog dog; Cat cat; Eagle eagle; Salmon salmon; processAnimal (dog); processAnimal (cat); processAnimal (eagle); processAnimal (salmon); std::vector<std::string> animalTypes = {"dog" , "cat" , "eagle" , "salmon" }; std::cout << "\nUsing factory pattern:" << std::endl; for (const auto & type : animalTypes) { auto animal = AnimalFactory::createAnimal (type); processAnimal (*animal); } }
多态的优缺点 优点 代码复用 :统一的接口可以处理不同类型的对象,减少重复代码扩展性 :新的派生类可以无缝集成到现有系统中,无需修改现有代码灵活性 :通过基类指针或引用可以动态选择合适的实现可维护性 :代码结构清晰,易于理解和维护抽象能力 :通过抽象类和接口可以定义清晰的行为契约解耦 :降低模块间的耦合度,提高系统的可测试性多态与设计模式 :支持多种设计模式,如策略模式、工厂模式、观察者模式等缺点 性能开销 :虚函数调用需要通过虚函数表查找,比普通函数调用慢内存开销 :每个包含虚函数的类都需要虚函数表,每个对象都需要虚指针复杂性 :复杂的继承层次可能导致代码难以理解和维护向下转型风险 :需要小心使用类型转换,避免运行时错误设计难度 :正确设计抽象接口需要丰富的经验二进制兼容性 :修改基类的虚函数可能破坏二进制兼容性内联限制 :虚函数调用通常难以内联,限制了编译器优化性能开销详细分析 虚函数调用开销 :
内存访问:需要访问vptr → vtable → 函数地址 分支预测:虚函数调用是间接分支,容易导致分支预测失败 缓存影响:vtable访问可能导致缓存未命中 性能数据 :
虚函数调用:约2-5个时钟周期的额外开销 普通函数调用:约0-1个时钟周期 内联函数:0个时钟周期(无调用开销) 多态的最佳实践 1. 正确使用虚函数 核心原则 :只对需要多态的函数使用虚函数,避免不必要的性能开销。
最佳实践 :
基类析构函数应该声明为virtual 派生类重写虚函数时使用override关键字 考虑使用final关键字防止不必要的覆盖 避免在构造函数和析构函数中调用虚函数 对于性能关键路径,考虑使用编译时多态替代运行时多态 高级技巧 :
使用[[nodiscard]]标记虚函数返回值,提高代码质量 考虑使用consteval(C++20+)在编译时计算多态相关值 使用std::variant(C++17+)和std::visit实现基于变体的多态 2. 合理设计抽象接口 核心原则 :抽象接口应该简洁明了,只包含必要的方法。
最佳实践 :
使用纯虚函数定义接口 接口应该符合单一职责原则 避免在接口中包含实现细节 考虑使用组合而非继承来扩展功能 接口应该稳定,避免频繁修改 设计模式应用 :
接口隔离原则 :将大接口拆分为小而专注的接口依赖倒置原则 :高层模块依赖抽象,而非具体实现开闭原则 :对扩展开放,对修改封闭3. 处理多态与异常 核心原则 :异常处理应该与多态设计相结合,确保异常能够正确传播。
最佳实践 :
异常类型应该有合理的层次结构 虚函数可以抛出异常,但派生类抛出的异常应该与基类兼容 析构函数不应该抛出异常 考虑使用RAII模式管理资源 使用异常规范(C++11前)或noexcept(C++11+)标记函数的异常行为 异常安全级别 :
无抛出保证 :函数不会抛出异常强异常安全 :如果抛出异常,程序状态保持不变基本异常安全 :如果抛出异常,程序状态仍然有效,但可能改变4. 性能优化策略 核心原则 :在性能关键的代码中,需要平衡多态的便利性和性能开销。
最佳实践 :
对于性能关键的代码,考虑使用编译时多态(模板) 避免深层的继承层次 合理使用内联函数 考虑使用CRTP(奇异递归模板模式)实现静态多态 使用std::function和lambda表达式实现轻量级多态 高级优化技术 :
虚函数表缓存 :在热点代码中缓存虚函数指针多态分派优化 :使用跳转表或其他技术优化分派SIMD与多态结合 :为不同类型提供SIMD优化的实现硬件感知优化 :根据目标硬件调整多态实现5. 类型转换与安全性 核心原则 :在多态系统中,类型转换应该安全可靠。
最佳实践 :
尽量避免向下转型 使用dynamic_cast进行安全的向下转型 考虑使用工厂模式或策略模式减少类型转换的需要 对于编译时已知的类型转换,使用static_cast 使用std::optional和std::variant替代一些类型转换场景 类型转换安全策略 :
运行时检查 :使用dynamic_cast并检查结果类型标识 :在基类中添加类型标识方法访问者模式 :使用访问者模式避免显式类型转换类型擦除 :使用类型擦除技术隐藏具体类型6. 现代C++特性的应用 核心原则 :利用现代C++特性提高多态代码的安全性和性能。
最佳实践 :
使用智能指针(std::unique_ptr, std::shared_ptr)管理多态对象的生命周期 利用C++20概念(Concepts)约束模板参数,实现更安全的静态多态 使用std::span(C++20+)和其他现代容器简化多态代码 利用结构化绑定(C++17+)和折叠表达式(C++17+)简化模板代码 使用模块(C++20+)提高编译速度和代码组织 现代C++多态模式 :
基于范围的for循环 :简化多态对象集合的遍历lambda表达式 :实现轻量级的函数对象协程 :在异步编程中实现多态行为反射 :使用C++23反射特性简化多态代码7. 测试与调试策略 核心原则 :多态代码需要专门的测试和调试策略,确保正确性和性能。
最佳实践 :
为每个派生类编写单元测试 测试多态行为,确保基类指针能正确调用派生类实现 使用静态分析工具检测多态相关的问题 性能分析:识别虚函数调用的热点 内存分析:检测多态对象的内存泄漏 调试技巧 :
使用调试器查看对象的vptr和vtable 打印对象的类型信息(使用typeid) 使用断言验证类型转换的安全性 日志记录:在关键多态操作中添加日志 多态的实际应用场景 1. 图形用户界面(GUI) 核心需求 :处理不同类型的UI组件,如按钮、文本框、列表等。
高级实现 :
事件系统 :使用多态实现事件分发和处理渲染系统 :支持不同渲染后端的多态接口布局系统 :基于多态的布局管理器主题系统 :通过多态实现可切换的UI主题1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 class Event {public : enum class Type { CLICK, KEY_PRESS, MOUSE_MOVE, RESIZE }; Type type; int x, y; char key; Event (Type t) : type (t), x (0 ), y (0 ), key (0 ) {} }; class Widget {public : virtual ~Widget () = default ; virtual void draw () const = 0 ; virtual void resize (int width, int height) = 0 ; virtual void setPosition (int x, int y) = 0 ; virtual bool handleEvent (const Event& event) = 0 ; virtual bool containsPoint (int x, int y) const = 0 ; struct State { int x, y, width, height; bool visible = true ; bool enabled = true ; } state; protected : Widget (int x, int y, int width, int height) : state{x, y, width, height} {} }; class Button : public Widget {private : std::string label; std::function<void ()> onClickCallback; public : Button (const std::string& label, int x, int y, int width, int height) : Widget (x, y, width, height), label (label) {} void draw () const override { std::cout << "Drawing button with label '" << label << "' at (" << state.x << ", " << state.y << ") size " << state.width << "x" << state.height << std::endl; } void resize (int width, int height) override { state.width = width; state.height = height; } void setPosition (int x, int y) override { state.x = x; state.y = y; } bool handleEvent (const Event& event) override { if (!state.visible || !state.enabled) return false ; if (event.type == Event::Type::CLICK && containsPoint (event.x, event.y)) { std::cout << "Button clicked: " << label << std::endl; if (onClickCallback) { onClickCallback (); } return true ; } return false ; } bool containsPoint (int x, int y) const override { return x >= state.x && x < state.x + state.width && y >= state.y && y < state.y + state.height; } void setOnClickCallback (std::function<void ()> callback) { onClickCallback = std::move (callback); } }; class TextBox : public Widget {private : std::string text; bool focused = false ; public : TextBox (const std::string& text, int x, int y, int width, int height) : Widget (x, y, width, height), text (text) {} void draw () const override { std::cout << "Drawing text box with text '" << text << "' at (" << state.x << ", " << state.y << ") size " << state.width << "x" << state.height; if (focused) { std::cout << " [FOCUSED]" ; } std::cout << std::endl; } void resize (int width, int height) override { state.width = width; state.height = height; } void setPosition (int x, int y) override { state.x = x; state.y = y; } bool handleEvent (const Event& event) override { if (!state.visible || !state.enabled) return false ; if (event.type == Event::Type::CLICK) { focused = containsPoint (event.x, event.y); return focused; } else if (event.type == Event::Type::KEY_PRESS && focused) { if (event.key == '\b' && !text.empty ()) { text.pop_back (); } else if (event.key >= 32 && event.key <= 126 ) { text += event.key; } std::cout << "Text box updated: '" << text << "'" << std::endl; return true ; } return false ; } bool containsPoint (int x, int y) const override { return x >= state.x && x < state.x + state.width && y >= state.y && y < state.y + state.height; } const std::string& getText () const { return text; } }; class Container : public Widget {private : std::vector<std::unique_ptr<Widget>> children; public : Container (int x, int y, int width, int height) : Widget (x, y, width, height) {} void addChild (std::unique_ptr<Widget> widget) { children.push_back (std::move (widget)); } void draw () const override { std::cout << "Drawing container at (" << state.x << ", " << state.y << ") size " << state.width << "x" << state.height << std::endl; for (const auto & child : children) { child->draw (); } } void resize (int width, int height) override { state.width = width; state.height = height; } void setPosition (int x, int y) override { state.x = x; state.y = y; } bool handleEvent (const Event& event) override { if (!state.visible || !state.enabled) return false ; for (auto it = children.rbegin (); it != children.rend (); ++it) { if ((*it)->handleEvent (event)) { return true ; } } return false ; } bool containsPoint (int x, int y) const override { return x >= state.x && x < state.x + state.width && y >= state.y && y < state.y + state.height; } }; class UIManager {private : std::unique_ptr<Container> rootContainer; public : UIManager () : rootContainer (std::make_unique <Container>(0 , 0 , 800 , 600 )) {} void addWidget (std::unique_ptr<Widget> widget) { rootContainer->addChild (std::move (widget)); } void drawAll () const { rootContainer->draw (); } void handleEvent (const Event& event) { rootContainer->handleEvent (event); } void resize (int width, int height) { rootContainer->resize (width, height); } }; void useGUI () { UIManager uiManager; auto button = std::make_unique <Button>("Click Me" , 100 , 100 , 120 , 40 ); button->setOnClickCallback ([]() { std::cout << "Button callback executed!" << std::endl; }); auto textBox = std::make_unique <TextBox>("Enter text here" , 100 , 160 , 200 , 40 ); uiManager.addWidget (std::move (button)); uiManager.addWidget (std::move (textBox)); uiManager.drawAll (); Event clickEvent (Event::Type::CLICK) ; clickEvent.x = 150 ; clickEvent.y = 120 ; uiManager.handleEvent (clickEvent); Event keyEvent (Event::Type::KEY_PRESS) ; keyEvent.key = 'H' ; uiManager.handleEvent (keyEvent); keyEvent.key = 'e' ; uiManager.handleEvent (keyEvent); keyEvent.key = 'l' ; uiManager.handleEvent (keyEvent); keyEvent.key = 'l' ; uiManager.handleEvent (keyEvent); keyEvent.key = 'o' ; uiManager.handleEvent (keyEvent); }
2. 数据库访问层 核心需求 :支持不同类型的数据库,如MySQL、PostgreSQL、SQLite等。
高级实现 :
连接池 :使用多态实现数据库连接池事务管理 :支持不同数据库的事务处理查询构建器 :基于多态的SQL查询构建ORM映射 :对象关系映射的多态实现1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 class ResultSet {public : virtual ~ResultSet () = default ; virtual bool next () = 0 ; virtual int getInt (int columnIndex) = 0 ; virtual std::string getString (int columnIndex) = 0 ; virtual double getDouble (int columnIndex) = 0 ; virtual bool getBoolean (int columnIndex) = 0 ; }; class Database {public : virtual ~Database () = default ; virtual void connect (const std::string& connectionString) = 0 ; virtual void disconnect () = 0 ; virtual bool isConnected () const = 0 ; virtual std::unique_ptr<ResultSet> executeQuery (const std::string& query) = 0 ; virtual int executeUpdate (const std::string& query) = 0 ; virtual void beginTransaction () = 0 ; virtual void commit () = 0 ; virtual void rollback () = 0 ; }; class MySQLDatabase : public Database {private : bool connected = false ; std::string connectionString; public : void connect (const std::string& connectionString) override { std::cout << "Connecting to MySQL database: " << connectionString << std::endl; this ->connectionString = connectionString; this ->connected = true ; } void disconnect () override { std::cout << "Disconnecting from MySQL database" << std::endl; this ->connected = false ; } bool isConnected () const override { return connected; } std::unique_ptr<ResultSet> executeQuery (const std::string& query) override { std::cout << "Executing MySQL query: " << query << std::endl; return nullptr ; } int executeUpdate (const std::string& query) override { std::cout << "Executing MySQL update: " << query << std::endl; return 0 ; } void beginTransaction () override { std::cout << "Starting MySQL transaction" << std::endl; } void commit () override { std::cout << "Committing MySQL transaction" << std::endl; } void rollback () override { std::cout << "Rolling back MySQL transaction" << std::endl; } }; class PostgreSQLDatabase : public Database {private : bool connected = false ; std::string connectionString; public : void connect (const std::string& connectionString) override { std::cout << "Connecting to PostgreSQL database: " << connectionString << std::endl; this ->connectionString = connectionString; this ->connected = true ; } void disconnect () override { std::cout << "Disconnecting from PostgreSQL database" << std::endl; this ->connected = false ; } bool isConnected () const override { return connected; } std::unique_ptr<ResultSet> executeQuery (const std::string& query) override { std::cout << "Executing PostgreSQL query: " << query << std::endl; return nullptr ; } int executeUpdate (const std::string& query) override { std::cout << "Executing PostgreSQL update: " << query << std::endl; return 0 ; } void beginTransaction () override { std::cout << "Starting PostgreSQL transaction" << std::endl; } void commit () override { std::cout << "Committing PostgreSQL transaction" << std::endl; } void rollback () override { std::cout << "Rolling back PostgreSQL transaction" << std::endl; } }; class DatabasePool {private : std::vector<std::unique_ptr<Database>> connections; std::queue<Database*> availableConnections; std::mutex mutex; std::condition_variable cv; int maxConnections; std::string connectionString; std::string dbType; public : DatabasePool (const std::string& type, const std::string& connStr, int maxConn = 10 ) : maxConnections (maxConn), connectionString (connStr), dbType (type) { initializePool (); } void initializePool () { for (int i = 0 ; i < maxConnections; ++i) { auto db = createDatabase (); if (db) { db->connect (connectionString); availableConnections.push (db.get ()); connections.push_back (std::move (db)); } } } std::unique_ptr<Database> createDatabase () { if (dbType == "mysql" ) { return std::make_unique <MySQLDatabase>(); } else if (dbType == "postgresql" ) { return std::make_unique <PostgreSQLDatabase>(); } else { throw std::invalid_argument ("Unknown database type: " + dbType); } } std::unique_ptr<Database, std::function<void (Database*)>> acquireConnection () { std::unique_lock<std::mutex> lock (mutex) ; cv.wait (lock, [this ]() { return !availableConnections.empty (); }); Database* db = availableConnections.front (); availableConnections.pop (); return std::unique_ptr<Database, std::function<void (Database*)>>( db, [this ](Database* db) { std::unique_lock<std::mutex> lock (mutex); availableConnections.push (db); cv.notify_one (); } ); } ~DatabasePool () { for (auto & conn : connections) { if (conn->isConnected ()) { conn->disconnect (); } } } }; class DatabaseFactory {public : static std::unique_ptr<Database> createDatabase (const std::string& type) { if (type == "mysql" ) { return std::make_unique <MySQLDatabase>(); } else if (type == "postgresql" ) { return std::make_unique <PostgreSQLDatabase>(); } else { throw std::invalid_argument ("Unknown database type: " + type); } } static std::unique_ptr<DatabasePool> createPool (const std::string& type, const std::string& connStr, int maxConn = 10 ) { return std::make_unique <DatabasePool>(type, connStr, maxConn); } }; class Transaction {private : Database& db; bool committed = false ; public : explicit Transaction (Database& database) : db(database) { db.beginTransaction (); } ~Transaction () { if (!committed) { try { db.rollback (); } catch (...) { } } } void commit () { db.commit (); committed = true ; } void rollback () { db.rollback (); committed = true ; } }; void useDatabase () { try { auto pool = DatabaseFactory::createPool ("mysql" , "host=localhost;port=3306;dbname=test;user=root;password=123456" , 5 ); auto db = pool->acquireConnection (); { Transaction tx (*db) ; db->executeUpdate ("INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com')" ); db->executeUpdate ("UPDATE settings SET value = '1' WHERE key = 'enabled'" ); tx.commit (); } auto result = db->executeQuery ("SELECT * FROM users" ); std::cout << "Database operations completed successfully" << std::endl; } catch (const std::exception& e) { std::cerr << "Error: " << e.what () << std::endl; } }
3. 日志系统 核心需求 :支持不同类型的日志输出,如控制台、文件、网络等。
高级实现 :
日志级别 :支持不同级别的日志(DEBUG、INFO、WARN、ERROR、FATAL)日志格式化 :可自定义的日志格式异步日志 :基于多态的异步日志系统日志轮转 :支持文件日志的自动轮转1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 enum class LogLevel { DEBUG, INFO, WARN, ERROR, FATAL }; class Logger {public : virtual ~Logger () = default ; virtual void log (LogLevel level, const std::string& message) = 0 ; virtual void logDebug (const std::string& message) = 0 ; virtual void logInfo (const std::string& message) = 0 ; virtual void logWarn (const std::string& message) = 0 ; virtual void logError (const std::string& message) = 0 ; virtual void logFatal (const std::string& message) = 0 ; virtual void setMinLevel (LogLevel level) = 0 ; }; class LogFormatter {public : virtual ~LogFormatter () = default ; virtual std::string format (LogLevel level, const std::string& message) = 0 ; }; class SimpleFormatter : public LogFormatter {public : std::string format (LogLevel level, const std::string& message) override { std::string levelStr; switch (level) { case LogLevel::DEBUG: levelStr = "DEBUG" ; break ; case LogLevel::INFO: levelStr = "INFO" ; break ; case LogLevel::WARN: levelStr = "WARN" ; break ; case LogLevel::ERROR: levelStr = "ERROR" ; break ; case LogLevel::FATAL: levelStr = "FATAL" ; break ; } auto now = std::chrono::system_clock::now (); auto time = std::chrono::system_clock::to_time_t (now); std::stringstream ss; ss << std::put_time (std::localtime (&time), "%Y-%m-%d %H:%M:%S" ); return "[" + ss.str () + "] [" + levelStr + "] " + message; } }; class DetailedFormatter : public LogFormatter {public : std::string format (LogLevel level, const std::string& message) override { std::string levelStr; switch (level) { case LogLevel::DEBUG: levelStr = "DEBUG" ; break ; case LogLevel::INFO: levelStr = "INFO" ; break ; case LogLevel::WARN: levelStr = "WARN" ; break ; case LogLevel::ERROR: levelStr = "ERROR" ; break ; case LogLevel::FATAL: levelStr = "FATAL" ; break ; } auto now = std::chrono::system_clock::now (); auto time = std::chrono::system_clock::to_time_t (now); auto ms = std::chrono::duration_cast <std::chrono::milliseconds>(now.time_since_epoch ()) % 1000 ; std::stringstream ss; ss << std::put_time (std::localtime (&time), "%Y-%m-%d %H:%M:%S" ) << "." << std::setfill ('0' ) << std::setw (3 ) << ms.count (); std::thread::id threadId = std::this_thread::get_id (); std::stringstream threadSs; threadSs << threadId; return "[" + ss.str () + "] [" + levelStr + "] [Thread: " + threadSs.str () + "] " + message; } }; class ConsoleLogger : public Logger {private : LogLevel minLevel = LogLevel::INFO; std::unique_ptr<LogFormatter> formatter; public : ConsoleLogger (std::unique_ptr<LogFormatter> fmt = std::make_unique <SimpleFormatter>()) : formatter(std::move (fmt)) {} void log (LogLevel level, const std::string& message) override { if (level < minLevel) return ; std::string formattedMessage = formatter->format(level, message); if (level >= LogLevel::ERROR) { std::cerr << formattedMessage << std::endl; } else { std::cout << formattedMessage << std::endl; } } void logDebug (const std::string& message) override { log (LogLevel::DEBUG, message); } void logInfo (const std::string& message) override { log (LogLevel::INFO, message); } void logWarn (const std::string& message) override { log (LogLevel::WARN, message); } void logError (const std::string& message) override { log (LogLevel::ERROR, message); } void logFatal (const std::string& message) override { log (LogLevel::FATAL, message); } void setMinLevel (LogLevel level) override { minLevel = level; } }; class FileLogger : public Logger {private : LogLevel minLevel = LogLevel::INFO; std::unique_ptr<LogFormatter> formatter; std::ofstream file; std::mutex mutex; public : FileLogger (const std::string& filename, std::unique_ptr<LogFormatter> fmt = std::make_unique <SimpleFormatter>()) : formatter(std::move (fmt)) { file.open (filename, std::ios::out | std::ios::app); if (!file) { throw std::runtime_error ("Failed to open log file: " + filename); } } ~FileLogger () override { if (file.is_open ()) { file.close (); } } void log (LogLevel level, const std::string& message) override { if (level < minLevel) return ; std::string formattedMessage = formatter->format(level, message); std::lock_guard<std::mutex> lock (mutex) ; if (file.is_open ()) { file << formattedMessage << std::endl; } } void logDebug (const std::string& message) override { log (LogLevel::DEBUG, message); } void logInfo (const std::string& message) override { log (LogLevel::INFO, message); } void logWarn (const std::string& message) override { log (LogLevel::WARN, message); } void logError (const std::string& message) override { log (LogLevel::ERROR, message); } void logFatal (const std::string& message) override { log (LogLevel::FATAL, message); } void setMinLevel (LogLevel level) override { minLevel = level; } }; class AsyncLogger : public Logger {private : std::unique_ptr<Logger> logger; std::queue<std::pair<LogLevel, std::string>> logQueue; std::mutex queueMutex; std::condition_variable cv; std::thread workerThread; std::atomic<bool > running = true ; public : explicit AsyncLogger (std::unique_ptr<Logger> logger) : logger(std::move(logger)) { workerThread = std::thread ([this ]() { while (running) { std::pair<LogLevel, std::string> logEntry; bool hasEntry = false ; { std::unique_lock<std::mutex> lock (queueMutex); cv.wait (lock, [this ]() { return !logQueue.empty () || !running; }); if (!logQueue.empty ()) { logEntry = logQueue.front (); logQueue.pop (); hasEntry = true ; } } if (hasEntry) { logger->log (logEntry.first, logEntry.second); } } }); } ~AsyncLogger () override { running = false ; cv.notify_one (); if (workerThread.joinable ()) { workerThread.join (); } } void log (LogLevel level, const std::string& message) override { std::unique_lock<std::mutex> lock (queueMutex) ; logQueue.emplace (level, message); cv.notify_one (); } void logDebug (const std::string& message) override { log (LogLevel::DEBUG, message); } void logInfo (const std::string& message) override { log (LogLevel::INFO, message); } void logWarn (const std::string& message) override { log (LogLevel::WARN, message); } void logError (const std::string& message) override { log (LogLevel::ERROR, message); } void logFatal (const std::string& message) override { log (LogLevel::FATAL, message); } void setMinLevel (LogLevel level) override { logger->setMinLevel (level); } }; class LogManager {private : std::vector<std::unique_ptr<Logger>> loggers; std::mutex mutex; public : void addLogger (std::unique_ptr<Logger> logger) { std::lock_guard<std::mutex> lock (mutex) ; loggers.push_back (std::move (logger)); } void log (LogLevel level, const std::string& message) { std::lock_guard<std::mutex> lock (mutex) ; for (const auto & logger : loggers) { logger->log (level, message); } } void logDebug (const std::string& message) { log (LogLevel::DEBUG, message); } void logInfo (const std::string& message) { log (LogLevel::INFO, message); } void logWarn (const std::string& message) { log (LogLevel::WARN, message); } void logError (const std::string& message) { log (LogLevel::ERROR, message); } void logFatal (const std::string& message) { log (LogLevel::FATAL, message); } void setMinLevel (LogLevel level) { std::lock_guard<std::mutex> lock (mutex) ; for (const auto & logger : loggers) { logger->setMinLevel (level); } } }; class LoggerFactory {public : static std::unique_ptr<Logger> createConsoleLogger (LogLevel minLevel = LogLevel::INFO, bool detailed = false ) { auto logger = std::make_unique <ConsoleLogger>( detailed ? std::make_unique <DetailedFormatter>() : std::make_unique <SimpleFormatter>() ); logger->setMinLevel (minLevel); return logger; } static std::unique_ptr<Logger> createFileLogger (const std::string& filename, LogLevel minLevel = LogLevel::INFO, bool detailed = false ) { auto logger = std::make_unique <FileLogger>( filename, detailed ? std::make_unique <DetailedFormatter>() : std::make_unique <SimpleFormatter>() ); logger->setMinLevel (minLevel); return logger; } static std::unique_ptr<Logger> createAsyncLogger (std::unique_ptr<Logger> logger) { return std::make_unique <AsyncLogger>(std::move (logger)); } static std::unique_ptr<LogManager> createLogManager () { return std::make_unique <LogManager>(); } }; void useLogger () { auto logManager = LoggerFactory::createLogManager (); auto consoleLogger = LoggerFactory::createConsoleLogger (LogLevel::DEBUG, true ); logManager->addLogger (std::move (consoleLogger)); auto fileLogger = LoggerFactory::createFileLogger ("application.log" , LogLevel::INFO, false ); auto asyncFileLogger = LoggerFactory::createAsyncLogger (std::move (fileLogger)); logManager->addLogger (std::move (asyncFileLogger)); logManager->logDebug ("This is a debug message" ); logManager->logInfo ("Application started" ); logManager->logWarn ("Low memory warning" ); logManager->logError ("Failed to connect to database" ); logManager->logFatal ("Critical system failure" ); std::cout << "Simulating long-running operation..." << std::endl; std::this_thread::sleep_for (std::chrono::seconds (2 )); logManager->logInfo ("Operation completed" ); logManager->logInfo ("Application exited" ); } class GlobalLogger {private : static std::unique_ptr<LogManager> instance; static std::once_flag initFlag; GlobalLogger () = default ; static void initialize () { instance = LoggerFactory::createLogManager (); auto consoleLogger = LoggerFactory::createConsoleLogger (LogLevel::INFO); instance->addLogger (std::move (consoleLogger)); } public : static LogManager& get () { std::call_once (initFlag, initialize); return *instance; } static void addLogger (std::unique_ptr<Logger> logger) { get ().addLogger (std::move (logger)); } static void setMinLevel (LogLevel level) { get ().setMinLevel (level); } static void debug (const std::string& message) { get ().logDebug (message); } static void info (const std::string& message) { get ().logInfo (message); } static void warn (const std::string& message) { get ().logWarn (message); } static void error (const std::string& message) { get ().logError (message); } static void fatal (const std::string& message) { get ().logFatal (message); } }; std::unique_ptr<LogManager> GlobalLogger::instance = nullptr ; std::once_flag GlobalLogger::initFlag; #define LOG_DEBUG(msg) GlobalLogger::debug(msg) #define LOG_INFO(msg) GlobalLogger::info(msg) #define LOG_WARN(msg) GlobalLogger::warn(msg) #define LOG_ERROR(msg) GlobalLogger::error (msg) #define LOG_FATAL(msg) GlobalLogger::fatal(msg) void useGlobalLogger () { auto fileLogger = LoggerFactory::createFileLogger ("application.log" , LogLevel::DEBUG, true ); GlobalLogger::addLogger (std::move (fileLogger)); LOG_DEBUG ("Global logger initialized" ); LOG_INFO ("Application starting" ); try { LOG_DEBUG ("Performing some operation" ); throw std::runtime_error ("Simulated error" ); } catch (const std::exception& e) { LOG_ERROR (std::string ("Exception caught: " ) + e.what ()); } LOG_INFO ("Application exiting" ); }
总结 多态是C++面向对象编程的核心特性之一,它通过接口与实现分离、运行时绑定、代码复用和扩展性,为构建复杂的软件系统提供了强大的工具。本章节深入探讨了多态的各种实现机制、高级应用和最佳实践,涵盖了从基础概念到专家级技术的全面内容。
关键要点 :
1. 多态的类型与实现 编译时多态 :通过函数重载、模板、CRTP等技术实现,具有零运行时开销运行时多态 :通过虚函数、纯虚函数和抽象类实现,提供更大的灵活性类型擦除 :通过基类指针、std::any、std::function等技术实现2. 底层实现与性能分析 虚函数表(vtable) :编译器为每个包含虚函数的类生成的静态数组虚指针(vptr) :每个对象中指向虚函数表的指针性能开销 :虚函数调用比普通函数调用慢约2-5个时钟周期优化策略 :缓存友好设计、分支预测优化、SIMD集成3. 现代C++特性的应用 概念(Concepts) :C++20引入的模板约束机制协变返回类型 :派生类虚函数可以返回基类虚函数返回类型的派生类型智能指针 :管理多态对象的生命周期结构化绑定 :简化多态代码的使用4. 高级设计模式 CRTP :奇异递归模板模式,实现静态多态工厂模式 :基于多态创建对象策略模式 :通过多态选择不同的算法实现观察者模式 :通过多态实现事件通知机制5. 最佳实践与设计原则 接口设计 :遵循单一职责原则,保持接口简洁继承层次 :保持浅而宽的继承层次,避免深层继承异常安全 :确保多态代码的异常安全性性能平衡 :在性能关键路径上合理选择多态实现方式6. 实际应用场景 图形用户界面 :处理不同类型的UI组件数据库访问 :支持不同类型的数据库系统日志系统 :实现灵活的日志记录和管理插件系统 :通过多态实现可扩展的插件架构通过合理应用多态,开发者可以创建更加灵活、可扩展和可维护的C++代码,充分发挥面向对象编程的优势。同时,结合现代C++特性和性能优化技术,可以在保持代码清晰性和可维护性的同时,获得优异的运行性能。
本章节提供的技术深度和实践指导,旨在帮助开发者从理解多态的基本概念,到掌握其高级应用,最终能够在实际项目中灵活运用多态技术解决复杂问题,构建高质量的C++应用程序。