C++单个类的所有对象是否共享虚函数表的验证
来源:互联网 发布:mac修容粉 编辑:程序博客网 时间:2024/06/06 17:18
今天偶然看到这个面试题,第一感觉是既然所有对象共享虚函数代码,那么虚函数指针对所有对象就是一样的,因此虚函数表也就是一样的,没有必要为每个对象复制一份一模一样的虚函数表。所以做个验证,在这儿记录一下。如有错误,欢迎留言指正,感谢感谢。
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;}
输出结果:
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()
输出f和g的地址以及对f和g进行调用是为了验证程序的正确性。无论是VS还是g++,两个对象的虚函数表地址都是一样的,说明两个对象共享虚函数表。
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;}
输出如下:
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()
可以看出,c1和c2的两个虚函数表地址仍然是一样的。
结论:如果一个类有虚函数,那么这个类的所有对象共享一个虚函数表。
阅读全文
0 0
- C++单个类的所有对象是否共享虚函数表的验证
- 多态中虚函数表的地址是所有对象共享的
- java线程对单个对象的共享的一些方式
- C++【String类】String头插单个字符,头删单个字符的函数实现
- 函数指针类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。 注意的是,编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一
- 静态函数里定义的变量,不为所有对象共享,类的静态变量和类外全局变量区别,静态函数和普通函数区别
- C++:类的成员函数存储方式(是否属于类的对象)
- Objective-c - 单个对象的内存管理(内存泄漏)
- PHP 验证身份证号是否正确的函数
- Hibernate查询对象所有字段,单个字段 ,几个字段取值的问题
- Hibernate查询对象所有字段,单个字段 ,几个字段取值的问题
- Hibernate查询对象所有字段,单个字段 ,几个字段取值的问题
- 获取单个页面的所有信息
- C++【String类】String查找单个字符,查找字符串的函数实现
- C++【String类】String删除单个字符,删除字符串的函数实现
- C++【String类】String插入单个字符,插入字符串的函数实现
- 能被某个类的所有实例对象共享,这样的变量称之为类变量
- 一个类的static变量在其所有实例化对象上是共享的
- 2018校招唯品会软件测试岗在线笔试
- DP——51nod1486 大大走格子
- java 将已有的字符串保存到txt文件中
- 反向传播算法
- (转)解决机器学习问题有通法!看这一篇就够了!
- C++单个类的所有对象是否共享虚函数表的验证
- 5.go slice, 切片与数组, map
- 7-18 日期格式化(5 分)
- Tomcat热部署方法(3种)
- vc获取windows设备枚举设备信息
- lsof命令、pidof命令和pgrep命令
- yum下载rpm包以及相关依赖包
- 快速排序Java实现--最简单的实现方法
- ES04--ElasticSearch vs Solr 优缺点