深入探索c++虚函数继承模型
2016-06-08 22:07
561 查看
关于c++虚函数的继承模型,在http://blog.csdn.net/haoel/article/details/1948051/一文中有详细的介绍,本文只是对虚函数继承的验证,具体如下。
示例代码:
当我们在
通过结果对比我们可以确定
1.在基类中对象b所占空间大小为8个字节(虚函数表指针+int型变量a),派生对象c所占空间大小为12字节(虚函数表指针4个字节+两个int整形的值);
2.基类的虚函数表一共占12个字节(包含三个函数的入口地址,每个函数的入口地址占4个字节),派生类虚函数表大小为20字节(重写了基类的f()函数的入口地址+基类中g()和h()的入口地址+派生类对象自身的g1()和h1()函数入口地址)
3.当偏量加到5时,出现访问冲突,说明派生类的虚函数表只有5个函数的入口地址;
示例代码:
<pre name="code" class="cpp">#include<stdlib.h> #include<iostream> #include<fstream> #include<stdio.h> #include<time.h> #include<memory.h> #include<math.h> #include<windows.h> #include<math.h> #include<conio.h> #include<iomanip> #include<string> #include<vector> using namespace std; class Base { public: int a; virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } virtual void h() { cout << "Base::h" << endl; } }; class Derived : public Base{ public: int b; virtual void f() { cout << "Derived::f" << endl; } virtual void g1() { cout << "Derived::g1" << endl; } virtual void h1() { cout << "Derived::h1" << endl; } }; int main(){ typedef void(*Fun)(void);//Fun是一个函数指针的类型声明,形参表为空,返回值也为空 Base b; b.a = 11; Fun pFun = NULL; cout << "对象的地址是:" << &b << endl;//整个对象b的地址 cout << "对象b中a的值是:" << *((int *)(&b)+1) << endl;//对象b中数据成员a的值 cout << "虚函数表地址:" << (int *)*(int*)(&b) << endl;//虚函数表的地址 //先得到vptr即虚表数组首地址,然后解引用得到vtbl数组中的第一个函数地址 cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl; cout << "虚函数表 — 第二个函数地址:" << (int*)*(int*)(&b) + 1 << endl; cout << "虚函数表 — 第三个函数地址:" << (int*)*(int*)(&b) + 2 << endl; pFun = (Fun)*((int*)*(int*)(&b));//将第一个函数地址赋值给pfun pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 0); // Base::f() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 1); // Base::g() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 2); // Base::h() pFun(); Derived c; c.a = 22; cout << "对象的地址是:" << &c << endl; cout << "虚函数表地址:" << (int*)(&c) << endl; //先得到vptr即虚表数组首地址,然后解引用得到vtbl数组中的第一个函数地址 cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&c) << endl; cout << "虚函数表 — 第二个函数地址:" << (int*)*(int*)(&c) + 1 << endl; cout << "虚函数表 — 第三个函数地址:" << (int*)*(int*)(&c) + 2 << endl; cout << "虚函数表 — 第四个函数地址:" << (int*)*(int*)(&c) + 3 << endl; cout << "虚函数表 — 第五个函数地址:" << (int*)*(int*)(&c) + 4 << endl; pFun = (Fun)*((int*)*(int*)(&c));//将第一个函数地址赋值给pfun pFun(); pFun = (Fun)*((int*)*(int*)(&c) + 0); // Base::f() pFun(); pFun = (Fun)*((int*)*(int*)(&c) + 1); // Base::g() pFun(); pFun = (Fun)*((int*)*(int*)(&c) + 2); // Base::h() pFun(); pFun = (Fun)*((int*)*(int*)(&c) + 3); // Base::h() pFun(); pFun = (Fun)*((int*)*(int*)(&c) + 4); // Base::h() pFun(); cout << sizeof(b) << endl;//一个基类对象所占空间的大小 cout << sizeof(c) << endl;//一个派生类对象所占大小 cout << sizeof(Derived) << endl; return 0; }
运行结果:
当我们在
pFun = (Fun)*((int*)*(int*)(&c) + 4); // Base::h() pFun();后面加上
pFun = (Fun)*((int*)*(int*)(&c) + 5); // Base::h() pFun();之后,运行结果如下:
通过结果对比我们可以确定
1.在基类中对象b所占空间大小为8个字节(虚函数表指针+int型变量a),派生对象c所占空间大小为12字节(虚函数表指针4个字节+两个int整形的值);
2.基类的虚函数表一共占12个字节(包含三个函数的入口地址,每个函数的入口地址占4个字节),派生类虚函数表大小为20字节(重写了基类的f()函数的入口地址+基类中g()和h()的入口地址+派生类对象自身的g1()和h1()函数入口地址)
3.当偏量加到5时,出现访问冲突,说明派生类的虚函数表只有5个函数的入口地址;
相关文章推荐
- 从汇编层面去理解c++中的虚函数
- 我理解的C++虚函数
- c++虚函数和抽象类
- C++ virtual function
- C++中virtual(虚函数)的用法详解
- 虚函数和纯虚函数
- 虚析构函数的作用
- C++虚函数在g++中的实现分析
- C++虚函数表实例分析
- C++第二次上机5-5
- c++ string函数精讲
- 哈夫曼树数据机构的建立及哈夫曼编码与解码的C++实现
- 类的继承与派生(Shape例子派生Rectangle和Circle,Rectangle派生出Square)
- C语言char*字符串数组和unsigned char[]数组的相互转换
- C++符号优先级
- 层序遍历二叉树(C语言+循环队列)
- GDI+ 如何绘制圆角矩形(vc++)
- 【C/C++】枚举类型举例
- error LNK2019
- C++构造函数和析构函数