【C++】Geekband-专题二:虚指针和内存分配
1. 传统继承类的设计
static void print_object(const char* name, void* this_, size_t size) {
void** ugly = reinterpret_cast<void**>(this_);
size_t i;
printf("created %s at address %p of size %zu\n", name, this_, size);
for(i = 0 ; i < size / sizeof(void*) ; i++) {
printf(" pointer[%zu] == %p\n", i, ugly[i]);
}
cout << "-------------------------------"<<endl;
}
class A {
public:
long iA;
long iAA;
A ():iA (1), iAA(10) {print_object(__FUNCTION__, this, sizeof(*this));
}
virtual void f() { cout << "A::f()" << endl; }
virtual void g() { cout << "A::g()" << endl; }
virtual void h() { cout << "A::h()" << endl; }
};
class B : public A {
public:
long iB;
B():iB(2) {
print_object(__FUNCTION__, this, sizeof(*this));
}
virtual void f() { cout << "B::f()" << endl; }
virtual void g_B() { cout << "B::g_B()" << endl; }
virtual void h_B() { cout << "B::h_B()" << endl; }
};
class C : public B{
public:
long iC;
C():iC(3) {
print_object(__FUNCTION__, this, sizeof(*this));
}
virtual void f() { cout << "C::f()" << endl; }
virtual void g_B() { cout << "C::g_B()" << endl; }
virtual void h_C() { cout << "C::h_C()" << endl; }
};
- A、B、C依次继承
- 并在构造过程中通过
print_object
输出构建信息
2. 构造Class C
,并通过指针来一次访问内容或调用函数
int main()
{
typedef void(*Fun)(void);
long** pVtab = nullptr;
Fun pFun = nullptr;
C c;
pVtab = (long**)&c;
long *cAsLong = (long *)&c;
cout << "C::vptr memory address is " << &cAsLong[0] <<endl;
cout << "[0] C::_vptr->" << endl;
cout << " No.\tMemory Address\t Value\t\tFunction" << endl;
for (int i=0; (Fun)pVtab[0][i] != nullptr; i++){
pFun = (Fun)pVtab[0][i];
cout << " ["<<i<<"]\t";
cout << " " << &pVtab[0][i]<<"\t";;
cout << " " << (void *)pVtab[0][i]<<"\t";;
pFun();
}
cout << " ----------------------------------" << endl;
cout << "[0] addr = " << &pVtab[0] << "\t";
cout << "value = " << pVtab[0] << endl;
cout << "[1] addr = "<< &pVtab[1] << "\t";
cout << "value = " << pVtab[1] << "\t";
cout << "A.iA = " << *((long *) &pVtab[1] )<< endl;
cout << c.iA << endl;
cout << "[2] addr = " << &pVtab[2] << "\t";
cout << "value = " << pVtab[2] << "\t";
cout << "A.iAA = " << *((long *) &pVtab[2]) << endl;
cout << "[3] addr = " << &pVtab[3] << "\t";
cout << "value = " << pVtab[3] << "\t";
cout << "B.iB = " << *((long *) &pVtab[3]) << endl;
cout << "[4] addr = " << &pVtab[4] << "\t";
cout << "value = " << pVtab[4] << "\t";
cout << "C.iC = " << *((long *) &pVtab[4]) << endl;
return 0;
pVtab
用于显示虚表的位置,并用于后续的直接调用- 通过循环,一次输出虚表中各个成员的地址和对应的存储内容
- 最后,通过直接调用相应的存储内容来调用成员或调用函数。
3. gdb的使用方法
- 编译过程
g++ -g -o test.cpp test
- gdb运行程序
(gdb) r
- gdb中设置断点
(gdb) break line_number
- gdb中查询虚表
(gdb) info vtbl c
- gdb中查询内存内容 - 选择输出的格式
(gdb) x /5xg 0xfffffffd70
(gdb) x /32xg 0x401440
4. 具体逻辑关系见下图
e-mail: kongww.nudt [AT] gmail.com
WeChat/QQ: 40804097