有这样三个类的声明:
class A {
public:
virtual void fun1() {
cout << "A::fun1" << endl;
}
};
class B : public A {
public:
virtual void fun1() {
cout << "B::fun1" << endl;
}
virtual void fun2() {
cout << "B::fun2" << endl;
}
};
class C : public B {
public:
virtual void fun2() {
cout << "C::fun2" << endl;
}
};
B *pb1 = new B;
B *pb2 = new C;
pb1->fun2(); // B::fun2
pb2->fun2(); // C::fun2
B继承A后,新声明了个虚函数fun2,并被C继承,此时用B的指针指向C的对象可以实现多态。然而观察内存发现B和C的虚函数表里只保存了fun1的地址,并没有fun2的地址:
即使直接观察内存也是没有的:
可以看到C的虚函数表里,第一个地址0x008814e7就是B::fun1的地址,而后一个地址0x008814dd却不是B::fun2或C::fun2的地址
那么,程序在运行时是怎么找到fun2的地址的呢?
大家讲道理2017-04-17 12:03:48
真實的情況是這樣的。你的B不只覆蓋了A,還增加了一個虛擬函數,所以B裡面就會有兩張虛函數表,一張用來保存fun1,一張用來保存fun2。
因此寫成C語言大概就這樣:
void A_fun1(A* this)
{
cout << "A::fun1" << endl;
}
void B_fun1(A* this)
{
cout << "B::fun1" << endl;
}
void B_fun2(B* this)
{
cout << "B::fun2" << endl;
}
void C_fun2(B* this)
{
cout << "C::fun2" << endl;
}
struct vtable_A
{
void (*fun1)(A*);
};
struct vtable_B
{
void (*fun2)(B*);
};
vtable_A vtable_A_instance_A = { &A_fun1 };
vtable_A vtable_A_instance_B = { &B_fun1 };
vtable_B vtable_B_instance_B = { &B_fun2 };
vtable_B vtable_B_instance_C = { &C_fun2 };
struct A
{
vtable_A* vtable;
};
struct B
{
A _A;
vtable_B* vtable;
};
struct C
{
B _B;
};
void ctor_A(A* a)
{
a->vtable = &vtable_A_instance_A;
}
void ctor_B(B* b)
{
ctor_A(&b._A);
b->_A.vtable = &vtable_A_instance_B;
b->vtable = &vtable_B_instance_B;
}
void ctor_C(C* c)
{
ctor_B(&c._B);
c._B.vtable = &vtable_B_instance_C;
}
int main()
{
B* pb1 = (B*)malloc(sizeof(B));
ctor_B(pb1);
C* temp = (C*)malloc(sizeof(C));
ctor_C(temp);
B* pb2 = &temp._B;
pb1->vtable->fun2(pb1);
pb2->vtable->fun2(pb1);
return 0;
}