【C++进阶】多态的理解 忘是亡心i 2024-04-22 12:12 37阅读 0赞 ## 一.多态是什么 ## > 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。 > > 对于多态,不同的对象传过去,会调用不同的函数; > > 即多态调用看的是指向的对象。 //A,B类中的func函数是个多态 class A { public: virtual void func() { cout << "A->func" << endl; } }; class B :public A { public: virtual void func() { cout << "B->func" << endl; } }; ### 动态绑定和静态绑定 ### 多态分为两种: 1.静态绑定,也称为静态多态,是在程序编译阶段确定的,例如:函数重载和模板; 2.动态绑定,也称为动态多态,是在程序运行阶段确定的,根据具体拿到的类型确定程序的 具体行为,调用具体的函数。 -------------------- ## 二.虚函数 ## 虚函数:即被virtual修饰的类成员函数称为虚函数; 虚函数一般是存在代码段(常量区)的,可能不同的编译器会不一样。 #### 纯虚函数与抽象类 #### 在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口 类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生 类才能实例化出对象。 抽象类的作用:抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。 ![ddaae44b21bb431d9591b96ecf414c0b.png][] #### 接口继承和实现继承 #### 实现继承:普通函数的继承是一种实现继承; 接口继承:虚函数的继承是一种接口继承,如果不实现多态,不要把函数定义成虚函数。 ### 虚函数与静态成员函数 ### 静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表,即静态成员函数不能设置成虚函数。 ### 虚函数与 inline 函数 ### inline函数可以设置成虚函数,不过编译器就忽略inline属性,这个函数就不再是inline,因为虚函数要放到虚表中去。 -------------------- ## 三.多态的条件 ## ### 虚函数重写(覆盖)条件 ### a.是虚函数,即要有 virtual ; b.虚函数满足三同(返回值,函数名,参数列表相同)即构成重写; 例外: a.派生类可以不加 virtual ,因为派生类已经继承了基类的 virtual; b.协变(基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象 的指针或者引用时,称为协变) ### 构成条件 ### > 1.调用的函数是重写的虚函数; > > 2.必须通过基类的指针或者引用调用虚函数。 ### 重写析构函数 ### > 其实编译后析构函数的名称统一处理成destructor,此时析构函数的函数名相同,参数列表也相同,再加上 virtual 修饰,此时就重写了基类和派生类中的析构函数,即构成了多态。 #### 结论 #### > 析构函数建议设置成虚函数,因为有时可能利用多态方式通过基类指针调用子类析构函 数,尤其是父类的析构函数强力建议设置为虚函数,这样动态释放父类指针所指的子类 对象时,能够达到析构的多态。 ### 重载,重定义(隐藏)与重写 ### 重载:在同一作用域,函数名相同,返回值可以不同,参数列表必须不同; 重定义(隐藏):在不同的作用域,一个在基类,一个在派生类,只要函数名相同就构成重定义; 重写:1.在不同的作用域,一个在基类,一个在派生类; 2.都必须是虚函数; 3.满足三同(函数名,返回值,参数列表相同(协变除外)); #### 总结 #### 1.重写比重定义的条件更加严苛; 2.两个基类和派生类的同名函数,不是重定义就是重写; class A { public: virtual void func() //func函数重写 { cout << "A->func" << endl; } }; class B :public A { public: virtual void func() { cout << "B->func" << endl; } }; void test(A& a) //基类引用 { a.func(); } int main() { A a; B b; test(a); //传A的对象,调用A类的函数 test(b); //传B的对象,调用B类的函数 return 0; } ### override 和 final ### override:检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错; final:修饰虚函数,表示该虚函数不能再被重写 class A { public: virtual void func1() final {} //func1不能被重写 virtual void func2() {} }; class B:public A { public: virtual void func2() override {} //检查 func2 是否正确重写 }; -------------------- ## 四.多态的原理 ## ### 虚函数表 ### 其实基类和派生类的虚函数都会被放进虚函数表(简称虚表)里,类实例化出对象后会生成一个指针(\_vfptr),指向虚函数表,其实虚函数表就是一个函数指针数组,里面存着虚函数的地址,一般情况这个数组最后面放了一个nullptr。 同一个类的对象共享一个虚表。 ![8492648069ce4a32b6b6e02149a66e4d.png][] ### 打印虚表 ### 因为虚表指针一般存在对象的前4个字节(64位则为前8个字节),我们可以通过强制类型转换拿到这个虚表指针。 typedef void (*FUNC_PTR) (); //重定义函数指针 void print(FUNC_PTR* table) { for (size_t i = 0; table[i] != nullptr; i++) //需要注意每次运行时最好重新生成以下解决方 //案,因为多次编译vs可能就没有这个nullptr了 { printf("%p : ", table[i]); FUNC_PTR f = table[i]; f(); //调用函数指针所指向的函数 } cout << endl; } class A { public: virtual void func1() { cout << "A->func1" << endl; } virtual void func2() { cout << "A->func2" << endl; } }; int main() { A a; int vft1 = *((int*)&a); print((FUNC_PTR*)vft1); return 0; } > 观察打印结果我们可以发现,打印的就是对象里的所有虚函数。 > > ![52f78d98e6564f7795ca5a15ee8510c1.png][] ### 虚表生成 ### 虚表指针其实是在初始化列表阶段初始化的,所以构造函数不能设置成虚函数; 虚表生成: a.先将基类中的虚表内容拷贝一份到派生类虚表中 ; b.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函 数; c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后; -------------------- > **??本篇文章到此就结束了, 若有错误或是建议的话,欢迎小伙伴们指出;?️?** > > **??希望小伙伴们能支持支持博主啊,你们的支持对我很重要哦;??** > > **??谢谢你的阅读。??** [ddaae44b21bb431d9591b96ecf414c0b.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/22/68e7777dbc304c50aa01019903fd5d9c.png [8492648069ce4a32b6b6e02149a66e4d.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/22/ce157c954f85401b818a1bbd906f4ec1.png [52f78d98e6564f7795ca5a15ee8510c1.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/22/883fb6468b75481a9f604c37590863d7.png
相关 进阶理解:面向对象编程中的继承和多态问题 面向对象编程(Object-Oriented Programming,OOP)中,继承和多态是两个核心概念。 1. 继承: 继承是子类自动获得父类所有属性和方法的一种机 痛定思痛。/ 2024年09月11日 19:12/ 0 赞/ 14 阅读
相关 C++进阶教程- 多态 多态的概念与分类 多态是面向对象程序设计(OOP)的四大特性之一(封装、继承、多态、抽象)。在OOP中,一个接口多种实现即为多态。C++中的多态性具体体现在编译和运行两个 旧城等待,/ 2022年12月23日 00:43/ 0 赞/ 176 阅读
相关 【C++】多态进阶 多态进阶 1. 多态实现原理探究 1.1 包含虚函数的类的大小 1.2 虚函数表 1.3 动态绑定与静态绑定 2. 单 旧城等待,/ 2022年10月30日 09:30/ 0 赞/ 146 阅读
相关 C++入门进阶之6: 多态性 1. 多态是指同样的消息被不同类型的对象接收时导致不同的行为,消息是指对类的成员函数的调用。 2. 多态的类型: 重载多态,强制多态,包含多态和参数多态。 朴灿烈づ我的快乐病毒、/ 2022年05月24日 23:47/ 0 赞/ 160 阅读
相关 Java进阶总结——多态 Java进阶总结——多态 1.多态 /\\ \ 多态 \ 1.将子类的对象赋值给父类的引用 \ 2.当用父类引用调用父类的方法时,执行的是子类重写的方法 \ 旧城等待,/ 2022年05月18日 05:44/ 0 赞/ 171 阅读
相关 C++进阶之多态全方位剖析 1.多态的概念 当不同的对象去完成某个行为时,会产生出不同的状态;通俗来说就是多种形态。 eg:买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买 爱被打了一巴掌/ 2022年02月27日 06:27/ 0 赞/ 212 阅读
还没有评论,来说两句吧...