C++中多态特性深入探究---虚函数
2017-08-26 15:48
585 查看
首先,多态是什么?
摘抄自 多态(维基百科):—— 多态(英语:polymorphism),是指计算机程序运行时,相同的消息可能会送给多个不同的类别之对象,而系统可依据对象所属类别,引发对应类别的方法,而有不同的行为。简单来说,所谓多态意指相同的消息给予不同的对象会引发不同的动作称之。
在cplusclpus中有这么一句话:
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage of this simple but powerful and versatile feature.
即,在C++中指向子类的指针和指向基类的指针是兼容的。
所以,在C++中,我们可以通过指针指向不同的对象来实现多态(引用和指针类似,虽然有些差别,但是这里不展开讨论)
虚函数机制
参考《Effective C++》条款07中对虚表指针以及虚函数表的讲解,这里阐述下虚函数机制的原理:—- 在C++中,若在类中定义了虚函数,则编译器会为改类生成一个虚函数表,这个表中保存了该类以及父类所有的虚函数,并在实例化该类时,会在类对象中添加一个虚表指针,这个指针就只向该虚表指针,当使用指针或引用调用函数时,C++会根据对象中保存的虚表指针查找需要调用的函数,具体的细节下面慢慢分析。
class Fa { int Fa_a; public: void foo() { cout << "父类的foo函数 \n"; } }; class childA:public Fa { int CA_a; public: void foo() { cout << "子类A的foo函数 \n"; } };
在没有定义虚函数时,内存布局中只存在父类和子类的数据成员对象
class Fa { int Fa_a; public: virtual void foo() { cout << "父类的foo函数 \n"; } }; class childA:public Fa { int CA_a; public: void foo() { cout << "子类A的foo函数 \n"; } };
在添加了虚函数后,内存布局中增加了一个vfptr,并且生成了一个vftable,分别是虚表指针和虚函数表。
class Fa { int Fa_a; public: virtual void foo() { cout << "父类的foo函数 \n"; } }; class childA:public Fa { int CA_a; };
class Fa { int Fa_a; }; class childA:public Fa { int CA_a; public: virtual void foo() { cout << "子类A的foo函数 \n"; } };
在这两个例子中需要注意两点:
当在父类中先定义虚函数时,vfptr出现在父类下面,当子类先定义虚函数时,vfptr出现在子类下面
当在子类中定义了和父类中虚函数相同的函数时,虚函数表中保存的是子类的虚函数,当子类中没有定义与父类虚函数相同的函数时,虚函数表中保存的是父类的虚函数。
—- 这里不难得出一下两点结论:
子类会继承父类的虚函数表,并且当子类定义了与父类相同的函数(返回值,函数签名都相同)时,子类的虚函数会覆盖父类的虚函数保存到虚函数表中。
当子类出现父类中没有的虚函数时,子类的虚函数会被添加到虚函数表中,并且偏移量大于任意父类的虚函数。
— 上面的例子还不是很清晰的说明了第二点,下面在放一个清晰一点的例子:
class Fa { int Fa_a; public: virtual void foo() { cout << "父类的foo函数 \n"; } virtual void FFF() { cout << ""; } }; class childA:public Fa { int CA_a; public: virtual void foo() { cout << "子类A的foo函数 \n"; } virtual void funcA() { cout << "子类A的func函数\n"; } };
这个例子可以让我们清楚的理解上面两点结论,父类中先定义了虚函数,于是vfptr在Fa下面,子类定义了与父类相同的函数,于是子类的虚函数覆盖了父类的虚函数,子类新增了虚函数,于是虚函数表中添加了该虚函数,并且在父类虚函数的后面。
理解了原理后我们就可以使用虚函数来实现多态了:
#include<iostream> using namespace std; class Fa { int Fa_a; public: virtual void foo() { cout << "父类的foo函数 \n"; } }; class childA:public Fa { int CA_a; public: virtual void foo() { cout << "子类A的foo函数 \n"; } }; class childB :public Fa { int CB_a; public: virtual void foo() { cout << "子类B的foo函数\n"; } }; void func() { Fa * ff = new Fa(); ff->foo(); ff =new childA(); ff->foo(); ff = new childB(); ff->foo(); } int main() { func(); system("pause"); return 0; }
可以看到,我们使用了同一个ff指针,却调用了三个不同的函数,这就是多态了。
下一篇会讲解虚函数的注意事项
相关文章推荐
- 深入剖析C++继承,多态以及隐藏(一)。(虚函数探究)
- 深入解析C++中的虚函数与多态
- 深入解析C++中的虚函数与多态
- 深入理解C++三大特性之一 ——多态
- 深入探究C++中虚函数和虚析构函数的实现原理
- 深入理解C++三大特性之一 ——多态
- C++多态:深入虚函数,理解晚绑定
- C++三大特性之多态(二)---深度剖析各种虚继承虚函数以及虚表的内容存放
- C++对象布局及多态之虚成员函数如何调用
- C++特性之多态
- 虚函数与纯虚函数(C++与Java虚函数的区别)的深入分析
- 深入C++ string.find()函数的用法总结
- 【一问一答】c++基础知识 ||类,模版,多态,虚函数
- 深入学习C++中的函数概念
- 深入理解C++对象模型-成员函数的本质以及虚函数的实现(非虚继承)
- C++中虚函数与多态实现
- [C++基础]重载、覆盖、多态与函数隐藏(4)
- C++中的多态与虚函数的内部实现
- 【继承与多态】C++:继承中的赋值兼容规则,子类的成员函数,虚函数(重写),多态
- c++ 多态深入理解