多态
2016-04-20 17:39
204 查看
多态概念:一种形式有多种实现形态静态多态:编译器在编译期间完成的,根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用哪个函数,如果有对应的函数就调用该函数否则出现编译错误。(比如函数重载)实现多态调动:基类必须加virtual关键字修饰,派生类可加可不加。(虚函数实现)动态绑定条件
(1)必须是虚函数(2)通过基类类型的引用或指针调用
赋值运算符重载、静态成员函数、友元函数不能定义为虚函数
友元函数、静态成员函数都没有this指针, 赋值运算符重载函数不是不能被派生类继承,而是被派生类的默认“赋值运算符重载函数”给覆盖了
继承体系同名成员函数的关系
1、重载
(1)同一作用域
(2)函数名相同/参数不同
(3)返回值可不同
2、重写(覆盖)
(1)不在同一作用域(分别在基类和派生类)
(2)函数名相同/参数相同/返回值相同(协变关系)
(3)基类类型必须有virtual关键字
(4)访问修饰符可以不用
3、重定义(隐藏)
(1)在不同作用域中(分别在基类和派生类)
(2)函数名相同
(3)在基类和派生类中只要不构成重写就是重定义
非虚拟继承【带虚函数的类】
Base类没有显式定义自己的构造函数,此时编译器会和成默认的构造函数,合成的构造函数中主要完成在对象头4个字节中填写虚表地址。(编译器自动定义的一个虚指针,存放虚表的地址)
注意:虚表是编译器在编译和链接完成之后就已经建立好了,在构造函数中只是将虚表的地址填写到对象的前4个字节
注意:同一个类的对象共用同一个虚表【单继承(派生类中没有虚函数覆盖)】
如果派生类没有对基类的虚函数进行重写时,派生类虚表的结构先是基类的虚函数,然后再加上自己的虚函数部分,虚函数的顺序为在类中声明的顺序。
【单继承(派生类中有虚函数覆盖)】
如果派生类中覆盖了基类的虚函数,派生类虚函数表的规则为:先将基类的虚表内容搬移过来,若派生类对基类中某个虚函数进行了重写,则会用派生类重写的虚函数地址替换掉虚表中相应位置的基类虚函数地址,替换完成之后将派生类自己新添加的虚函数地址按照声明的顺序添加进虚函数表
【多继承(派生类不覆盖基类虚函数)】
【多继承(派生类覆盖基类虚函数)】
虚拟继承
编译器为派生类合成的默认构造函数任务分析:
虚拟继承派生类对象模型分析
(1)必须是虚函数(2)通过基类类型的引用或指针调用
赋值运算符重载、静态成员函数、友元函数不能定义为虚函数
友元函数、静态成员函数都没有this指针, 赋值运算符重载函数不是不能被派生类继承,而是被派生类的默认“赋值运算符重载函数”给覆盖了
继承体系同名成员函数的关系
1、重载
(1)同一作用域
(2)函数名相同/参数不同
(3)返回值可不同
2、重写(覆盖)
(1)不在同一作用域(分别在基类和派生类)
(2)函数名相同/参数相同/返回值相同(协变关系)
(3)基类类型必须有virtual关键字
(4)访问修饰符可以不用
3、重定义(隐藏)
(1)在不同作用域中(分别在基类和派生类)
(2)函数名相同
(3)在基类和派生类中只要不构成重写就是重定义
非虚拟继承【带虚函数的类】
class Base { public: virtual void FunTest1() { cout<<"Base::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base::FunTest2()"<<endl; } int _data1; }; int main() { Base b; b._data1 = 0x01; return 0; }
Base类没有显式定义自己的构造函数,此时编译器会和成默认的构造函数,合成的构造函数中主要完成在对象头4个字节中填写虚表地址。(编译器自动定义的一个虚指针,存放虚表的地址)
注意:虚表是编译器在编译和链接完成之后就已经建立好了,在构造函数中只是将虚表的地址填写到对象的前4个字节
注意:同一个类的对象共用同一个虚表【单继承(派生类中没有虚函数覆盖)】
class Base { public: virtual void FunTest1() {cout<<"Base::FunTest1()"<<endl;} virtual void FunTest2() {cout<<"Base::FunTest2()"<<endl;} int _data1; }; class Derive:public Base { public: virtual void FunTest3() {cout<<"Derive::FunTest3()"<<endl;} virtual void FunTest4() {cout<<"Derive::FunTest4()"<<endl;} int _data2; };
如果派生类没有对基类的虚函数进行重写时,派生类虚表的结构先是基类的虚函数,然后再加上自己的虚函数部分,虚函数的顺序为在类中声明的顺序。
【单继承(派生类中有虚函数覆盖)】
class Base { public: virtual void FunTest1() { cout<<"Base::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base::FunTest2()"<<endl; } int _data1; }; class Derive:public Base { public: virtual void FunTest1() { cout<<"Derive::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"Derive::FunTest3()"<<endl; } virtual void FunTest4() { cout<<"Derive::FunTest4()"<<endl; } int _data2; }; int main() { PrintVtable(); return 0; }
如果派生类中覆盖了基类的虚函数,派生类虚函数表的规则为:先将基类的虚表内容搬移过来,若派生类对基类中某个虚函数进行了重写,则会用派生类重写的虚函数地址替换掉虚表中相应位置的基类虚函数地址,替换完成之后将派生类自己新添加的虚函数地址按照声明的顺序添加进虚函数表
【多继承(派生类不覆盖基类虚函数)】
class Base { public: virtual void FunTest1() { cout<<"Base::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base::FunTest2()"<<endl; } int _data1; }; class Base1 { public: virtual void FunTest3() { cout<<"Base1::FunTest3()"<<endl; } virtual void FunTest4() { cout<<"Base1::FunTest4()"<<endl; } int _data2; }; class Derive:public Base, public Base1 { public: virtual void FunTest5() { cout<<"Derive::FunTest5()"<<endl; } int _data3; }; int main() { cout<<"sizeof(Derive) = "<<sizeof(Derive)<<endl; Derive d; d._data1 = 0x01; d._data2 = 0x02; d._data3 = 0x03; PrintVtable(); return 0; }
【多继承(派生类覆盖基类虚函数)】
class Base { public: virtual void FunTest1() { cout<<"Base::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base::FunTest2()"<<endl; } int _data1; }; class Base1 { public: virtual void FunTest3() { cout<<"Base1::FunTest3()"<<endl; } virtual void FunTest4() { cout<<"Base1::FunTest4()"<<endl; } int _data2; }; // 这次将继承列表中Base和Base1的位置互换 class Derive:public Base1, public Base { public: virtual void FunTest1() { cout<<"Derive::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"Derive::FunTest3()"<<endl; } virtual void FunTest5() { cout<<"Derive::FunTest5()"<<endl; } int _data3; }; int main() { PrintVtable(); return 0; }
虚拟继承
// 没有虚函数覆盖,但派生类有自己的虚函数 class Base { public: virtual void FunTest1() { cout<<"Base::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base::FunTest2()"<<endl; } int _data1; }; class Derive:virtual public Base { public: virtual void FunTest3() { cout<<"Derive::FunTest3()"<<endl; } virtual void FunTest4() { cout<<"Derive::FunTest4()"<<endl; } int _data2; };虚拟继承编译器为派生类合成的默认构造函数分析
编译器为派生类合成的默认构造函数任务分析:
虚拟继承派生类对象模型分析
相关文章推荐
- C#与.net高级编程 C#的多态介绍
- C#中面向对象编程机制之多态学习笔记
- C#中的多态深入理解
- C#中多态、重载、重写区别分析
- 设计引导--一个鸭子游戏引发的设计理念(多态,继承,抽象,接口,策略者模式)
- C# 面向对象三大特性:封装、继承、多态
- javascript每日必学之多态
- c#基础学习之多态
- PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)
- 从汇编看c++中多态的应用
- javascript 面向对象全新理练之继承与多态
- Java多态的使用注意事项
- C#使用虚拟方法实现多态
- 实例讲解PHP面向对象之多态
- C#中多态现象和多态的实现方法
- C++基础之this指针与另一种“多态”
- 深入解析C++中的虚函数与多态
- C++多态的实现及原理详细解析
- PHP5中实现多态的两种方法实例分享
- 举例讲解PHP面对对象编程的多态