朱金灿
《深入浅出MFC》在第二章中说:虚函数表的内容是依据类中的虚函数声明次序,一一填入函数指针。派生类会继承基类的虚函数表(以及其它可以继承的成员),当
我们在派生类中改写虚函数时,虚函数表就受了影响:表中元素所指的函数地址
将不再是基类的函数地址,而是派生类的函数地址。
测试程序:
#include <iostream.h>
#include <stdio.h>
class ClassA
{
public:
int m_data1;
int m_data2;
void func1() { }
void func2() { }
virtual void vfunc1() { }
virtual void vfunc2() { }
};
class ClassB : public ClassA
{
public:
int m_data3;
void func2() { }
virtual void vfunc1() { }
};
class ClassC : public ClassB
{
public:
int m_data1;
int m_data4;
void func2() { }
virtual void vfunc1() { }
};
void main()
{
cout << sizeof(ClassA) << endl;
cout << sizeof(ClassB) << endl;
cout << sizeof(ClassC) << endl;
ClassA a;
ClassB b;
ClassC c;
b.m_data1 = 1;
b.m_data2 = 2;
b.m_data3 = 3;
c.m_data1 = 11;
c.m_data2 = 22;
c.m_data3 = 33;
c.m_data4 = 44;
c.ClassA::m_data1 = 111;
cout << b.m_data1 << endl;
cout << b.m_data2 << endl;
cout << b.m_data3 << endl;
cout << c.m_data1 << endl;
cout << c.m_data2 << endl;
cout << c.m_data3 << endl;
cout << c.m_data4 << endl;
cout << c.ClassA::m_data1 << endl;
cout << &b << endl;
cout << &(b.m_data1) << endl;
cout << &(b.m_data2) << endl;
cout << &(b.m_data3) << endl;
cout << &c << endl;
cout << &(c.m_data1) << endl;
cout << &(c.m_data2) << endl;
cout << &(c.m_data3) << endl;
cout << &(c.m_data4) << endl;
cout << &(c.ClassA::m_data1) << endl;
}
执行结果是:
12
16
24
1
2
3
11
22
33
111
0X0064FDCC
0X0064FDD0
0X0064FDD4
0X0064FDD8
0X0064FDB0
0X0064FDC0
0X0064FDB8
0X0064FDBC
0X0064FDC4
0X0064FDB4
我在想这个例子能说明问题吗?不能说明问题。我觉得应该这样才能说明问
题:不是说假如派生类中改写虚函数时,虚函数表就受了影响:表中元素所指的
函数地址将不再是基类的函数地址,而是派生类的函数地址吗?那应该写两个程
序,一个是派生类中没有改写虚函数,然后比较派生类的虚函数表和基类的虚函
数表看函数地址有没有变化;另一个是派生类中改写了虚函数,然后比较派生类
的虚函数表和基类的虚函数表,看函数地址有没有变化。
下面是我的证明程序:
// 虚函数.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <iostream.h>
void DispVFT(DWORD* pVFT)
{
printf("VFT Pointer:%p\n" , pVFT);
printf("Begin\n");
DWORD* p = (DWORD* )*pVFT;//得到VFT的首址
while(*p)
{
printf("VF:%p , %p\n", p , *p);
p++;
}
printf("End\n\n");
}
class A
{
public:
A()
{
printf("in A\n");
DispVFT((DWORD*)this);
}
~A(){}
void fun()
{
cout<<"A::fun\n";
}
virtual void vfun()
{
cout<<"A::vfun\n";
}
};
class B:public A
{
public:
B()
{
printf("in B\n");
DispVFT((DWORD*)this);
}
~B(){}
void fun()
{
cout<<"B::fun\n";
}
virtual void vfun()
{
cout<<"B::vfun\n";
}
virtual void vfun2()
{
cout<<"B::vfun2\n";
}
};
void test(A* p)
{
p->fun();
p->vfun();
}
int main(int argc, char* argv[])
{
A a;
B b;
// test(&a);
test(&b);
return 0;
}
上面是改变了虚函数的例子,你会发现虚函数的地址确实改变了,但是如果把类b的改写虚函数的部分去掉,你会发现类b的虚函数地址并没有改变。
评论