C++单个类的所有对象是否共享虚函数表的验证
2017-09-18 13:40
369 查看
今天偶然看到这个面试题,第一感觉是既然所有对象共享虚函数代码,那么虚函数指针对所有对象就是一样的,因此虚函数表也就是一样的,没有必要为每个对象复制一份一模一样的虚函数表。所以做个验证,在这儿记录一下。如有错误,欢迎留言指正,感谢感谢。
输出结果:
输出f和g的地址以及对f和g进行调用是为了验证程序的正确性。无论是VS还是g++,两个对象的虚函数表地址都是一样的,说明两个对象共享虚函数表。
输出如下:
可以看出,c1和c2的两个虚函数表地址仍然是一样的。
结论:如果一个类有虚函数,那么这个类的所有对象共享一个虚函数表。
1. 单一虚函数表
验证代码如下:#include <bits/stdc++.h> using namespace std; typedef long long ll; class A { public: A() { cout << "A()" << endl; } virtual void f() { cout << "f()" << endl; } virtual void g() { cout << "g()" << endl; } virtual ~A() { cout << "~A()" << endl; } }; typedef void(*Func)(); int main() { A a1, a2; ll* vptr; vptr = (ll*)*(ll*)(&a1); cout << "a1虚函数表地址: "<< vptr << endl; Func f = (Func)(*vptr); cout << "a1.f()地址: " << (ll*)f << endl; f(); f = (Func)*(vptr+1); cout << "a1.g()地址: " << (ll*)f << endl; f(); vptr = (ll*)*(ll*)(&a2); cout << "a2虚函数表地址: " << vptr << endl; f = (Func)(*vptr); cout << "a2.f()地址: " << (ll*)f << endl; f(); f = (Func)*(vptr + 1); cout << "a2.g()地址: " << (ll*)f << endl; f(); return 0; }
输出结果:
VS2017 x64平台 | Ubuntu1604 64位(g++5.4.0) |
---|---|
A() A() a1虚函数表地址: 00007FF7FB04ADB8 a1.f()地址: 00007FF7FB041456 f() a1.g()地址: 00007FF7FB0414A1 g() a2虚函数表地址: 00007FF7FB04ADB8 a2.f()地址: 00007FF7FB041456 f() a2.g()地址: 00007FF7FB0414A1 g() ~A() ~A() | A() A() a1虚函数表地址:0x400f20 a1.f()地址: 0x400d3e f() a1.g()地址: 0x400d6a g() a2虚函数表地址: 0x400f20 a2.f()地址: 0x400d3e f() a2.g()地址: 0x400d6a g() ~A() ~A() |
2. 多个虚函数表
既然单一虚函数表类的对象都共享虚函数表,那么无论继承类的对象有多少个虚函数表,这些虚函数表应该都是共享的。下面验证:#include <bits/stdc++.h> using namespace std; typedef long long ll; class A { public: virtual void fA() { cout << "fA()" << endl; } virtual void gA() { cout << "gA()" << endl; } }; class B { public: virtual void fB() { cout << "fB()" << endl; } virtual void gB() { cout << "gB()" << endl; } }; class C: public A, public B { }; typedef void(*Func)(); int main() { C c1, c2; ll* vptr; vptr = (ll*)*(ll*)(&c1); cout << "c1虚函数表1地址: "<< vptr << endl; Func f = (Func)(*vptr); cout << "c1.fA()地址: " << (ll*)f << endl; f(); f = (Func)*(vptr+1); cout << "a1.gA()地址: " << (ll*)f << endl; f(); vptr = (ll*)*(ll*)(&c2); cout << "c2虚函数表1地址: " << vptr << endl; f = (Func)(*vptr); cout << "a2.fA()地址: " << (ll*)f << endl; f(); f = (Func)*(vptr + 1); cout << "a2.gA()地址: " << (ll*)f << endl; f(); cout << endl; vptr = (ll*)*((ll*)(&c1)+1); cout << "c1虚函数表2地址: " << vptr << endl; f = (Func)(*vptr); cout << "c1.fB()地址: " << (ll*)f << endl; f(); f = (Func)*(vptr + 1); cout << "a1.gB()地址: " << (ll*)f << endl; f(); vptr = (ll*)*((ll*)(&c2)+1); cout << "c2虚函数表2地址: " << vptr << endl; f = (Func)(*vptr); cout << "a2.fB()地址: " << (ll*)f << endl; f(); f = (Func)*(vptr + 1); cout << "a2.gB()地址: " << (ll*)f << endl; f(); return 0; }
输出如下:
VS2017 x64平台 | Ubuntu1604 64位(g++5.4.0) |
---|---|
c1虚函数表1地址: 00007FF6BACCBE18 c1.fA()地址: 00007FF6BACC12F3 fA() a1.gA()地址: 00007FF6BACC12B7 gA() c2虚函数表1地址: 00007FF6BACCBE18 a2.fA()地址: 00007FF6BACC12F3 fA() a2.gA()地址:00007FF6BACC12B7 gA() c1虚函数表2地址: 00007FF6BACCBE38 c1.fB()地址: 00007FF6BACC1244 fB() a1.gB()地址: 00007FF6BACC11DB gB() c2虚函数表2地址: 00007FF6BACCBE38 a2.fB()地址: 00007FF6BACC1244 fB() a2.gB()地址: 00007FF6BACC11DB gB() | c1虚函数表1地址: 0x401028 c1.fA()地址: 0x400d76 fA() a1.gA()地址: 0x400da2 gA() c2虚函数表1地址: 0x401028 a2.fA()地址: 0x400d76 fA() a2.gA()地址: 0x400da2 gA() c1虚函数表2地址: 0x401048 c1.fB()地址: 0x400dce fB() a1.gB()地址: 0x400dfa gB() c2虚函数表2地址: 0x401048 a2.fB()地址: 0x400dce fB() a2.gB()地址: 0x400dfa gB() |
结论:如果一个类有虚函数,那么这个类的所有对象共享一个虚函数表。
相关文章推荐
- 函数指针类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。 注意的是,编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一
- Delphi与C++之间通过实现函数与对象共享
- 在Delphi与C++之间实现函数与对象共享
- 《C++第七周实验报告1-1》---含有静态数据成员和成员函数的Time类:类中所有的对象共有的数据
- 使用arguments对象验证函数的参数是否合法
- 在Delphi与C++之间实现函数与对象共享
- C++:类的成员函数存储方式(是否属于类的对象)
- C++第七周任务【任务1】含有静态数据成员和成员函数的Time类:类中所有的对象共有的数据
- 在Delphi与C++之间实现函数与对象共享
- 在Delphi与C++之间实现函数与对象共享
- arguments对象验证函数的参数是否合法
- 多态中虚函数表的地址是所有对象共享的
- 在Delphi与C++之间实现函数与对象共享
- 静态函数里定义的变量,不为所有对象共享,类的静态变量和类外全局变量区别,静态函数和普通函数区别
- 在Delphi与C++之间实现函数与对象共享
- 多态中虚函数表的地址是所有对象共享的
- 如何判断一个C++对象是否在堆上(通过GetProcessHeaps取得所有堆,然后与对象地址比较即可),附许多精彩评论
- 【c++】虚函数对对象大小的影响
- [转]浅析C++中虚函数的调用及对象的内部布局(利用汇编深刻理解C++虚函数底层实现机制)