笔记:C++虚函数
来源:互联网 发布:数据库输入数据语句 编辑:程序博客网 时间:2024/05/21 10:29
C++的多态性分为两种:静态多态(编译时多态)和动态多态(运行时多态)。静态多态主要通过重载和模板来实现,动态多态是子类覆盖父类的虚函数,定义一个父类的指针,使指针指向子类实例,这样,父类就可以访问子类的方法,如果把父类的指针指向不同的子类实例,父类就可以访问不同的方法。
class Base {public: int data; void myFunc() { cout << "myFunc" << endl; } virtual void f() { cout << "Base::f()" << endl; } virtual void g() { cout << "Base::g()" << endl; } virtual void h() { cout << "Base::h()" << endl; }};class Derive : public Base {public: virtual void g() { cout << "Derive::g()" << endl; }};Base b;Base *ptr = new Derive();ptr->g(); //Derive::g()
在创建带有虚函数的类的实例时,会创建一个指向虚函数表的指针,这个指针被存在实例的开始处,虚函数表中保存着虚函数的地址,如图:
我们可以这样获取到虚函数的地址:&b表示类的首地址,由于类内存表中第一个位置存的是指针,所以先把地址强制转换成指针类型,就可以取出第一个值
*(int*)(&b)
,这个值就是指向虚函数的指针vptr(g++中指向虚函数表的指针放在开始处),vptr就是虚函数表的首地址,同理,虚函数表中存的是指针,所以强制转换后取值*(int*)*(int*)(&b)
就是函数 f 的地址,*((int*)*(int*)(&b)+1)
就是 g 的地址。要想输出虚函数,需要强制转换成函数指针。 typedef void(*pfunc)(void); Base b; pfunc p; p = (pfunc)*((int*)*(int*)(&b)+1); //强制转换成函数指针 p(); //Base::g();
注:忽略了一点,64位时指针是8个字节,而不是4个字节,所以,上述int*中的int改为long更恰当。
子类继承基类时,虚函数表中会包含子类和基类的全部虚函数
class Derive : public Base{public: virtual void df() { cout << "Derive::df()" << endl; virtual void dg() { cout << "Derive::dg()" << endl; virtual void dh() { cout << "Derive::dh()" << endl;}
如果子类的虚函数覆盖了父类的虚函数,虚函数表中父类的虚函数将会被子类的虚函数替代。
class Derive : public Base{public: virtual void f() { cout << "Derive1::f()" << endl; virtual void dg() { cout << "Derive1::dg()" << endl; virtual void dh() { cout << "Derive1::dh()" << endl;}Derive d;Base * b = &d;b->f(); //Derive::f()
所以,前面的例子中,父类的指针Base * ptr = new Derive(),访问 f 方法时(ptr->f()),访问到的是子类的方法。
多重继承时,有几个含有虚函数的父类,就会创建几个指向虚函数表的指针,每个虚函数表都存着对应的父类的虚函数的地址,其中,子类的虚函数地址保存在第一个父类的虚函数表中。
class Base1 {public: virtual void f() { cout << "Base1::f()" << endl; } virtual void g() { cout << "Base1::g()" << endl; } virtual void h() { cout << "Base1::h()" << endl; }};class Base2 {public: virtual void f() { cout << "Base2::f()" << endl; } virtual void g() { cout << "Base2::g()" << endl; } virtual void h() { cout << "Base2::h()" << endl; }};class Derive : public Base1, public Base2 {public: virtual void df() { cout << "Derive::df()" << endl; };Derive d;Base1 * ptr1 = &d;Base2 * ptr2 = &d;ptr1->f(); //Base1::f()ptr2->f(); //Base2::f()
两个父类Base1和Base2的指针虽然都指向子类,但是其实地址是不同的,ptr1对应的是vptr1指向的对象,ptr2对应的是vptr2指向的对象。
子类覆盖父类方法时:
class Derive : public Base1, public Base2 {public: virtual void f() { cout << "Derive::f()" << endl; }Derive d;Base1 * ptr1 = &d;Base2 * ptr2 = &d;ptr1->f(); //Derive::f()ptr2->f(); //Derive::f()
阅读全文
0 0
- 学习笔记3-C++-虚函数
- C++:函数<学习笔记>
- C函数使用笔记
- C语言:函数笔记
- 【笔记-C语言】 函数
- C语言函数使用笔记
- [C++]C++小笔记 ----- 函数
- C语言scanf函数笔记
- c 语言 笔记 函数 数组
- 007-函数-C语言笔记
- C语言之函数笔记
- C学习笔记之函数
- c语言笔记6-函数
- C语言笔记__函数
- C/C学习笔记/函数与程序结构
- 多态性与虚函数——C/C++学习笔记
- #C/C++笔记#C++虚函数的作用和使用方法
- C++(笔记)纯虚函数(抽象类)
- lombok的安装
- ARM开发(10)基于STM32的通用定时器中断控制蜂鸣器响
- PHP实现微信支付功能开发+实例代码
- QAQ & 君临天下 || 天行九歌
- 8.11 2575 给出字符串
- 笔记:C++虚函数
- Ubuntu1604 下编译并使用tensorflow c++库
- Laravel 中点赞功能实现
- webSQL
- 高级网络定制
- C++格式化字符
- HDU 5649 DZY Loves Sorting (二分 + 线段树)
- 多校联萌(三)QAQ & ORZ 的签到题
- MOOC清华《程序设计基础》期末考试第6题:鸡兔同笼问题