- 相同类的不同对象共享同一虚函数表。
- 任何函数指针通过 cout 直接输出为 1,与原文描述有出入,也未找到 linux 每个表的结尾统一表示,待研究。
- 用long 类型指针,应其长度和所在机器指针长度一致。
$ g++ test.cpp -o test && ./test
==== vitual function table ====
[0] --> Derive::f --> Base1::g --> Base1::h --> Derive::g1 --> []
[1] --> Derive::f --> Base2::g --> Base2::h --> []
[2] --> Derive::f --> Base3::g --> Base3::h --> []
==== virtual function table shared or not ====
pVtab:0x55c77563fbe8
pVtab2:0x55c77563fbe8
Share virtual function table between different instances of same class!
==== function pointer output with cout ====
(long*)pFun: 0xfffffffffffffff8
pFun: 1
(long*)pFun: 0xfffffffffffffff0
pFun: 1
(long*)pFun: 0x55c77543b2ba
pFun: 1
(long*)pFun: 0x7fb203e414f8
pFun: 1
(long*)pFun: 0x55c77543d518
pFun: 1
(long*)pFun: 0x300000000
pFun: 1
(long*)pFun: 0x55c77543a50a
pFun: 1
Function pointer have same output with cout.
// test.cpp
#include <iostream>
#include <string>
#include <sstream>
#include <map>
using namespace std;
class Base1 {
public:
virtual string f() { ostringstream oss; oss << "Base1::f"; return oss.str(); }
virtual string g() { ostringstream oss; oss << "Base1::g"; return oss.str(); }
virtual string h() { ostringstream oss; oss << "Base1::h"; return oss.str(); }
};
class Base2 {
public:
virtual string f() { ostringstream oss; oss << "Base2::f"; return oss.str(); }
virtual string g() { ostringstream oss; oss << "Base2::g"; return oss.str(); }
virtual string h() { ostringstream oss; oss << "Base2::h"; return oss.str(); }
};
class Base3 {
public:
virtual string f() { ostringstream oss; oss << "Base3::f"; return oss.str(); }
virtual string g() { ostringstream oss; oss << "Base3::g"; return oss.str(); }
virtual string h() { ostringstream oss; oss << "Base3::h"; return oss.str(); }
};
class Derive : public Base1, public Base2, public Base3 {
public:
virtual string f() { ostringstream oss; oss << "Derive::f"; return oss.str(); }
virtual string g1() { ostringstream oss; oss << "Derive::g1"; return oss.str(); }
};
string testFun() {
return "xxxx";
}
//typedef string(*Fun)(void);
using Fun = string(*)(void);
int main() {
Fun pFun = NULL;
Derive d;
long** pVtab = (long**)&d;
map<int,int> len_map = {{0,4},{1,3},{2,3}};
#if 1
cout << endl << "==== vitual function table ====" << endl;
for (int i = 0; i < 3; ++i) {
cout << " [" << i << "]";
for (int j = 0; j < len_map[i]; ++j) {
pFun = (Fun)*((long*)*((long*)&d+i)+j);
cout << " --> " << pFun();
}
cout << " --> []" << endl;
}
#endif
#if 1
cout << endl << "==== virtual function table shared or not ====" << endl;
Derive d2;
long** pVtab2 = (long**)&d2;
cout << " pVtab:" << *pVtab << endl;
cout << "pVtab2:" << *pVtab2 << endl;
if (*pVtab == *pVtab2) {
cout << "Share virtual function table between different instances of same class!" << endl;
}
#endif
#if 0
//Base1's vtable
pFun = (Fun)*((long*)*((long*)&d+0)+0);
//pFun = (Fun)pVtab[0][0];
cout << pFun() << endl;
pFun = (Fun)*((long*)*((long*)&d+0)+1);
//pFun = (Fun)pVtab[0][1];
cout << pFun() << endl;
pFun = (Fun)*((long*)*((long*)&d+0)+2);
//pFun = (Fun)pVtab[0][2];
cout << pFun() << endl;
//Derive's vtable
pFun = (Fun)*((long*)*((long*)&d+0)+3);
//pFun = (Fun)pVtab[0][3];
cout << pFun() << endl;
//The tail of the vtable
pFun = (Fun)*((long*)*((long*)&d+0)+4);
//pFun = (Fun)pVtab[0][4];
cout<<pFun<<endl;
//Base2's vtable
//pFun = (Fun)*((long*)*((long*)&d+1)+0);
pFun = (Fun)pVtab[1][0];
cout << pFun() << endl;
pFun = (Fun)pVtab[1][1];
cout << pFun() << endl;
pFun = (Fun)pVtab[1][2];
cout << pFun() << endl;
//The tail of the vtable
pFun = (Fun)pVtab[1][3];
cout<<pFun<<endl;
//Base3's vtable
pFun = (Fun)*((long*)*((long*)&d+2)+0);
//pFun = (Fun)pVtab[2][0];
cout << pFun() << endl;
pFun = (Fun)pVtab[2][1];
cout << pFun() << endl;
pFun = (Fun)pVtab[2][2];
cout << pFun() << endl;
//The tail of the vtable
pFun = (Fun)*((long*)*((long*)&d+2)+3);
//pFun = (Fun)pVtab[2][3];
cout<<pFun<<endl;
return 0;
#endif
#if 1
cout << endl << "==== function pointer output with cout ====" << endl;
pFun = (Fun)*((long*)*((long*)&d+0)+4);
cout << "(long*)pFun: " << (long*)pFun << endl;
cout << "pFun: " << pFun << endl;
pFun = (Fun)*((long*)*((long*)&d+1)+3);
cout << "(long*)pFun: " << (long*)pFun << endl;
cout << "pFun: " << pFun << endl;
pFun = (Fun)*((long*)*((long*)&d+2)+2);
cout << "(long*)pFun: " << (long*)pFun << endl;
cout << "pFun: " << pFun << endl;
pFun = (Fun)*((long*)*((long*)&d+2)+3);
cout << "(long*)pFun: " << (long*)pFun << endl;
cout << "pFun: " << pFun << endl;
pFun = (Fun)*((long*)*((long*)&d+2)+4);
cout << "(long*)pFun: " << (long*)pFun << endl;
cout << "pFun: " << pFun << endl;
pFun = (Fun)*((long*)*((long*)&d+2)+5);
cout << "(long*)pFun: " << (long*)pFun << endl;
cout << "pFun: " << pFun << endl;
pFun = &testFun;
cout << "(long*)pFun: " << (long*)pFun << endl;
cout << "pFun: " << pFun << endl;
cout << "Function pointer have same output with cout." << endl;
#endif
}