浅析C++多态及其实现模式
2016-04-19 22:56
459 查看
一. 多态的实现--虚表
1.多态就是多种形态。在C++中,对同一父类和子类构造出的不同对象发出同一条指令,需要它们完成不同的工作,就需要在父类和子类写出相同函数名的函数方法,并用虚函数区分它们。父类的指针/引用调用重写的虚函数,当父类指针/引用指向父类对象时调用的是父类的虚函数,指向子类对象时调用的是子类的虚函数。
2.虚函数表是通过一块连续内存来存储虚函数的地址。这张表解决了继承、虚函数(重写)的问题。在有虚函数的对象实例中都存在一张虚函数表,虚函数表就像一张地图,指明了实际应该调用的虚函数函数。
4.同一类的对象共用同一虚表
二. 单继承&多继承的对象模型
1.单继承:
2.多继承
三. 静态多态和动态多态
1.静态多态就是重载,因为是在编译期决议确定,所以称为静态多态。
2.动态多态就是通过继承重写基类的虚函数实现的多态,因为是在运行时决议确定,所以称为动态多态。
四. 菱形虚拟继承的对象模型
可见,在虚拟继承中,无论是几重继承,最终子类的虚函数表总是与继承列表的第一个父类的虚函数表合并在一起,但是有覆盖的虚函数,自然去覆盖父类的同名虚函数,并合并在该父类的虚表中。
1.多态就是多种形态。在C++中,对同一父类和子类构造出的不同对象发出同一条指令,需要它们完成不同的工作,就需要在父类和子类写出相同函数名的函数方法,并用虚函数区分它们。父类的指针/引用调用重写的虚函数,当父类指针/引用指向父类对象时调用的是父类的虚函数,指向子类对象时调用的是子类的虚函数。
2.虚函数表是通过一块连续内存来存储虚函数的地址。这张表解决了继承、虚函数(重写)的问题。在有虚函数的对象实例中都存在一张虚函数表,虚函数表就像一张地图,指明了实际应该调用的虚函数函数。
//带虚函数的类 class Base { public: virtual void func1() { cout << "Base::func1()" << endl; } virtual void func2() { cout << "Base::func2()" << endl; } private: int a; }; void Test1() { Base b1; }3.带虚函数的类的模型结构
4.同一类的对象共用同一虚表
void Test2() { Base b1, b2, b3; }
二. 单继承&多继承的对象模型
1.单继承:
class Base { public: virtual void func1() { cout << "Base::func1()" << endl; } virtual void func2() { cout << "Base::func2()" << endl; } private: int a; }; class Derive :public Base { public: virtual void func1() { cout << "Derive::func1" << endl; } virtual void func3() { cout << "Derive::func3" << endl; } virtual void func4() { cout << "Derive::func4" << endl; } private: int b; }; typedef void(*FUNC) (); void PrintVTable(int* VTable) { cout << " 虚表地址>" << VTable << endl; for (int i = 0; VTable[i] != 0; ++i) { printf(" 第%d个虚函数地址 :0X%x,->", i, VTable[i]); FUNC f = (FUNC)VTable[i]; f(); } cout << endl; } void Test1() { Base b1; Derive d1; int* VTable1 = (int*)(*(int*)&b1); int* VTable2 = (int*)(*(int*)&d1); PrintVTable(VTable1); PrintVTable(VTable2); }
2.多继承
class Base1 { public: virtual void func1() { cout << "Base1::func1" << endl; } virtual void func2() { cout << "Base1::func2" << endl; } private: int b1; }; class Base2 { public: virtual void func1() { cout << "Base2::func1" << endl; } virtual void func2() { cout << "Base2::func2" << endl; } private: int b2; }; class Derive : public Base1, public Base2 { public: virtual void func1() { cout << "Derive::func1" << endl; } virtual void func3() { cout << "Derive::func3" << endl; } private: int d1; }; typedef void(*FUNC) (); void PrintVTable(int* VTable) { cout << " 虚表地址>" << VTable << endl; for (int i = 0; VTable[i] != 0; ++i) { printf(" 第%d个虚函数地址 :0X%x,->", i, VTable[i]); FUNC f = (FUNC)VTable[i]; f(); } cout << endl; } void Test1() { Derive d1; int* VTable = (int*)(*(int*)&d1); PrintVTable(VTable); // Base2虚函数表在对象Base1后面 VTable = (int *)(*((int*)&d1 + sizeof(Base1) / 4)); PrintVTable(VTable); }
三. 静态多态和动态多态
1.静态多态就是重载,因为是在编译期决议确定,所以称为静态多态。
2.动态多态就是通过继承重写基类的虚函数实现的多态,因为是在运行时决议确定,所以称为动态多态。
class Base { public: virtual void func1() { cout << "Base::func1" << endl; } virtual void func2() { cout << "Base::func2" << endl; } void display() { cout << "display()" << endl; } void display(int i) { cout << "display(int i)->" << i << endl; } private: int a; }; class Derive :public Base { public: virtual void func1() { cout << "Derive::func1" << endl; } virtual void func3() { cout << "Derive::func3" << endl; } virtual void func4() { cout << "Derive::func4" << endl; } private: int b; }; void func(Base& b) { b.func1(); b.display(); b.display(10); } void Test1() { Base b1; Derive d1; func(b1); func(d1); }
四. 菱形虚拟继承的对象模型
class A { public: virtual void FunTest1() { cout << "A::FunTest1()" << endl; } virtual void FunTest2() { cout << "A::FunTest2()" << endl; } private: int _a; }; class B1 :virtual public A { public: virtual void FunTest3() { cout << "B1::FunTest3()" << endl; } virtual void FunTest4() { cout << "B2::FunTest4()" << endl; } private: int _b1; }; class B2 :virtual public A { public: virtual void FunTest1() { cout << "B2::FunTest1()" << endl; } virtual void FunTest4() { cout << "B2::FunTest4()" << endl; } private: int _b2; }; class C :public B1, public B2 { public: virtual void FunTest1() { cout << "C::FunTest1()" << endl; } virtual void FunTest5() { cout << "C::FunTest5()" << endl; } private: int _c; }; void Test1() { C c; c.FunTest5(); }
可见,在虚拟继承中,无论是几重继承,最终子类的虚函数表总是与继承列表的第一个父类的虚函数表合并在一起,但是有覆盖的虚函数,自然去覆盖父类的同名虚函数,并合并在该父类的虚表中。
相关文章推荐
- c#中虚函数的相关使用方法
- C#与.net高级编程 C#的多态介绍
- C#中面向对象编程机制之多态学习笔记
- C#中的多态深入理解
- C#中多态、重载、重写区别分析
- 设计引导--一个鸭子游戏引发的设计理念(多态,继承,抽象,接口,策略者模式)
- C++虚函数及虚函数表简析
- C++之普通成员函数、虚函数以及纯虚函数的区别与用法要点
- 构造函数不能声明为虚函数的原因及分析
- C++虚函数表实例分析
- C++虚函数的实现机制分析
- C++中虚函数与纯虚函数的用法
- C# 面向对象三大特性:封装、继承、多态
- javascript每日必学之多态
- c#基础学习之多态
- 深入探讨C++父类子类中虚函数的应用
- PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)
- 从汇编看c++中多态的应用
- javascript 面向对象全新理练之继承与多态
- Java多态的使用注意事项