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;}

输出结果:

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()


输出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;}

输出如下:

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()


可以看出,c1和c2的两个虚函数表地址仍然是一样的。

结论:如果一个类有虚函数,那么这个类的所有对象共享一个虚函数表。

阅读全文
0 0