【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
欢迎来到一整颗红豆的博客✨,一个关于探索技术的角落,记录学习的点滴📖,分享实用的技巧🛠️,偶尔还有一些奇思妙想💡
本文由一整颗红豆原创✍️,感谢支持❤️!请尊重原创📩!欢迎评论区留言交流🌟
个人主页 👉 一整颗红豆
本文专栏 ➡️C++ 进阶之路
礼器九鼎,釉下乾坤,多态中的 "风水寻龙诀"
- 多态的概念
- 编译时多态(静态多态)
- `编译时多态的实现方式有,函数重载,运算符重载和模板。`
- 函数重载 `Function Overloading`
- 运算符重载(`Operator Overloading`)
- 模板(`Templates`)
- 编译时多态的特点
- 静态绑定(`Static Binding`)
- 类型安全(`Type Safety`)
- 无运行时开销
- 代码膨胀(`Code bloat`)
- 运行时多态(动态多态)
- 认识虚函数(`Virtual function`)
- 虚函数的重写/覆盖(`override`和`final`)
- 纯虚函数(`Pure Virtual Function`)和抽象类
- 虚析构函数(`Virtual Destructor`)
- 协变(`Covariant Return Types`)
- 重载(`Overload`)、重写(`Override`)、隐藏(`Hide`)的对比
- 重载(`Overload`)
- 重写(`Override`)
- 隐藏(`Hide`)
- 多态的原理
- 虚函数表(`vtable`)
- 虚函数表的概念
- 虚函数表的生成规则
- 多态是如何实现的
- 动态绑定和静态绑定
- 虚函数表的位置
- 总结多态调用
- 写在最后
多态的概念
众所周知,面向对象有三大特性,封装、继承和多态!
多态(Polymorphism) 是面向对象编程的核心特性,允许用统一的接口操作不同类型的对象,并根据对象实际类型执行不同的行为。C++中的多态分为编译时多态和运行时多态。
编译时多态(静态多态)
编译时多态(Compile-Time Polymorphism) 又称为 静态多态,是一种在 代码编译阶段就能确定具体调用行为的机制。它的核心特点是 基于静态类型系统,通过代码结构直接决定调用哪个函数或操作,无需运行时动态查找。
编译时多态的实现方式有,函数重载,运算符重载和模板。
函数重载 Function Overloading
- 通过 参数列表不同(类型/数量/顺序)定义同名函数
示例:
void print(int x) { std::cout std::cout std::cout print(10); // 调用 print(int) print(3.14); // 调用 print(double) print("Hello"); // 调用 print(const char*) } private: double real; double imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i) {} // 重载 + 运算符 Complex operator+(const Complex &other) { return Complex(real + other.real, imag + other.imag); } void print() { std::cout // 运算符重载调用 Complex c1(1, 2); Complex c2(3, 4); Complex c3 = c1 + c2; std::cout return (a b) ? a : b; } std::cout public: void push(const T &item) { _elements.push_back(item); } T pop() {} private: std::vector Stack add(3, 5); // 编译时直接绑定到函数A add(3.0, 5.0); // 编译时直接绑定到函数B return 0; } return (a b) ? a : b; } int main() { Max(3, 5.0); // 编译出错:T 同时推导为 int 和 double,类型不一致 return 0; } return x * x; } int main() { square(5); // 生成 int square(int x) { return x*x; } square(3.14); // 生成 double square(double x) { return x*x; } return 0; } T data; /*...*/ }; int main() { Wrapper public: virtual void speak() { // 使用 virtual 关键字 std::cout public: void speak() override { // 使用 override 明确重写(C++11) std::cout Animal *animal = new Dog(); animal-speak(); // 输出 "Woof!"(调用 Dog 的实现) delete animal; return 0; } public: virtual void func(int) {} }; class Derived : public Base { public: void func(double) {} // 参数类型不一致,未覆盖基类 func(int) }; public: void func(int) override {} // 使用 override 强制编译器检查覆盖 }; public: void func() {} // 非虚函数 }; class Derived : public Base { public: void func() {} // 隐藏基类函数,无法多态调用 }; public: virtual void Drive() final {} }; class Benz : public Car { public: virtual void Drive() { std::cout public: virtual void func(int val = 1) { std::cout func(); } }; class B : public A { public: void func(int val = 0) { std::cout B *p = new B; p-test(); return 0; } public: virtual void sound() const = 0; // 纯虚函数 virtual ~Animal() {} // 虚析构函数(重要!) }; // 派生类必须实现 sound() class Dog : public Animal { public: void sound() const override { // 重写纯虚函数 std::cout public: void sound() const override { // 重写纯虚函数 std::cout public: virtual void sound() const = 0; }; // 纯虚函数的默认实现(罕见用法)必须实在类外实现的! void Animal::sound() const { std::cout public: void sound() const override { Animal::sound(); // 调用基类的默认实现 std::cout // 基类(无虚析构函数) public: ~Base() { std::cout // 派生类(持有动态资源) public: int *data; Derived() { data = new int[100]; // 动态分配内存 } ~Derived() { delete[] data; // 释放内存 std::cout Base *obj = new Derived(); // 基类指针指向派生类对象 delete obj; // 仅调用了Base基类的析构函数 return 0; } public: virtual ~Base() { // 声明为虚析构函数 std::cout public: ~Derived() override { // 重写虚析构函数 std::cout Base *obj = new Derived(); delete obj; // 正确调用Derived和Base的析构函数 return 0; } public: virtual Fruit* clone() const { // 虚函数,返回Fruit*(基类指针) return new Fruit(*this); } virtual ~Fruit() {} }; // 派生类 class Apple : public Fruit { public: Apple* clone() const override { // 协变:返回Apple*(派生类指针) return new Apple(*this); } void sayName() const { std::cout Fruit* fruit = new Apple(); // 基类指针指向派生类对象 Fruit* cloned = fruit-clone(); // 调用派生类的clone() // 验证协变特性 if (Apple* apple = dynamic_cast apple-sayName(); // 成功调用Apple特有方法 } else { std::cout public: // 重载示例 int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } // 参数类型不同 int add(int a, int b, int c) { return a + b + c; } // 参数数量不同 }; public: void func() { std::cout std::cout public: // 隐藏基类的所有 func 函数(包括重载) void func() { std::cout Derived d; d.func(); // 正确:调用 Derived::func() // d.func(1); // 错误!Base::func(int) 被隐藏 d.Base::func(1); // 正确:显式调用基类函数 return 0; } public: virtual void Func1() { std::cout Base b; std::cout public: virtual void func1() {} virtual void func2() {} int data; }; public: void func1() override {} // 重写基类的func1 virtual void func3() {} // 新增虚函数 }; virtual void f1(); }; class Base2 { virtual void f2(); }; class Derived : public Base1, public Base2 { void f1() override {} void f2() override {} }; public: void nonVirtualFunc() { std::cout public: void nonVirtualFunc() { std::cout Base* obj = new Derived(); obj-nonVirtualFunc(); // 输出 "Base"(静态绑定) delete obj; return 0; } /* ... */ } func(); // 静态绑定 /* ... */ } templateFunc(42); // 编译时生成针对int的版本 public: virtual void virtualFunc() { std::cout public: void virtualFunc() override { std::cout Base* obj = new Derived(); obj-virtualFunc(); // 输出 "Derived"(动态绑定) delete obj; return 0; } public: virtual ~Base() {} // 虚析构函数 }; class Derived : public Base { public: ~Derived() override { /* 释放派生类资源 */ } }; Base* obj = new Derived(); delete obj; // 动态调用~Derived() public: virtual void func(int val = 1) { std::cout func(); } }; class B : public A { public: void func(int val = 0) { std::cout B *p = new B; p-test(); return 0; } public: virtual void func1() { cout cout cout public: // 重写基类的func1 virtual void func1() { cout cout cout int i = 0; static int j = 1; int *p1 = new int; const char *p2 = "xxxxxxxx"; printf("栈:%p\n", &i); printf("静态区:%p\n", &j); printf("堆:%p\n", p1); printf("常量区:%p\n", p2); Base b; Derive d; Base *p3 = &b; Derive *p4 = &d; printf("Person虚表地址:%p\n", *(int *)p3); printf("Student虚表地址:%p\n", *(int *)p4); printf("虚函数地址:%p\n", &Base::func1); printf("普通函数地址:%p\n", &Base::func5); return 0; }
- 通过 参数列表不同(类型/数量/顺序)定义同名函数
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。