正文

《深入浅出MFC》的一个例子的一点问题2007-01-14 15:33:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/clever101/22569.html

分享到:

                                   朱金灿

    《深入浅出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的虚函数地址并没有改变。

 

阅读(2687) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册