C++对象的内存布局下
来源:互联网 发布:直销软件制作xazxrj 编辑:程序博客网 时间:2024/06/07 01:18
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://haoel.blog.51cto.com/313033/124561
重复继承
函数。
字节),而且还有自己的虚函数,自己overwrite覆盖了超类的函数,f1() 为自己的虚函数。
class B
{
public:
int ib;
char cb;
public:
B():ib(0),cb('B') {}
virtual void f() { cout << "B::f()" << endl;}
virtual void Bf() { cout << "B::Bf()" << endl;}
};
class B1 : public B
{
public:
int ib1;
char cb1;
public:
B1():ib1(11),cb1('1') {}
virtual void f() { cout << "B1::f()" << endl;}
virtual void f1() { cout << "B1::f1()" << endl;}
virtual void Bf1() { cout << "B1::Bf1()" << endl;}
};
class B2: public B
{
public:
int ib2;
char cb2;
public:
B2():ib2(12),cb2('2') {}
virtual void f() { cout << "B2::f()" << endl;}
virtual void f2() { cout << "B2::f2()" << endl;}
virtual void Bf2() { cout << "B2::Bf2()" << endl;}
};
class D : public B1, public B2
{
public:
int id;
char cd;
public:
D():id(100),cd('D') {}
virtual void f() { cout << "D::f()" << endl;}
virtual void f1() { cout << "D::f1()" << endl;}
virtual void f2() { cout << "D::f2()" << endl;}
virtual void Df() { cout << "D::Df()" << endl;}
};
下)
typedef void(*Fun)(void);
int** pVtab = NULL;
Fun pFun = NULL;
D d;
pVtab = (int**)&d;
cout << "[0] D::B1::_vptr->" << endl;
pFun = (Fun)pVtab[0][0];
cout << " [0] "; pFun();
pFun = (Fun)pVtab[0][1];
cout << " [1] "; pFun();
pFun = (Fun)pVtab[0][2];
cout << " [2] "; pFun();
pFun = (Fun)pVtab[0][3];
cout << " [3] "; pFun();
pFun = (Fun)pVtab[0][4];
cout << " [4] "; pFun();
pFun = (Fun)pVtab[0][5];
cout << " [5] 0x" << pFun << endl;
cout << "[1] B::ib = " << (int)pVtab[1] << endl;
cout << "[2] B::cb = " << (char)pVtab[2] << endl;
cout << "[3] B1::ib1 = " << (int)pVtab[3] << endl;
cout << "[4] B1::cb1 = " << (char)pVtab[4] << endl;
cout << "[5] D::B2::_vptr->" << endl;
pFun = (Fun)pVtab[5][0];
cout << " [0] "; pFun();
pFun = (Fun)pVtab[5][1];
cout << " [1] "; pFun();
pFun = (Fun)pVtab[5][2];
cout << " [2] "; pFun();
pFun = (Fun)pVtab[5][3];
cout << " [3] "; pFun();
pFun = (Fun)pVtab[5][4];
cout << " [4] 0x" << pFun << endl;
cout << "[6] B::ib = " << (int)pVtab[6] << endl;
cout << "[7] B::cb = " << (char)pVtab[7] << endl;
cout << "[8] B2::ib2 = " << (int)pVtab[8] << endl;
cout << "[9] B2::cb2 = " << (char)pVtab[9] << endl;
cout << "[10] D::id = " << (int)pVtab[10] << endl;
cout << "[11] D::cd = " << (char)pVtab[11] << endl;
下面是对于子类实例中的虚函数表的图:
和B2中,其有B1的成员在D继承而来的。所以,如果我们使用以下语句,则会产生二义性编译错误:
D d;
d.ib = 0; //二义性错误
d.B1::ib = 1; //正确
d.B2::ib = 2; //正确
中还是有两个实例,这种继承造成了数据的重复,我们叫这种继承为重复继承。重复的基类数据成员可能并不是我们想要的。所以,C++上述的“重复继承”只需要把B1的语法中加上virtual 在查看D和GCC下的程序大家可以根据我给出的程序自己仿照着写一个去试一试):
int** pVtab = NULL;
Fun pFun = NULL;
B1 bb1;
pVtab = (int**)&bb1;
cout << "[0] B1::_vptr->" << endl;
pFun = (Fun)pVtab[0][0];
cout << " [0] ";
pFun(); //B1::f1();
cout << " [1] ";
pFun = (Fun)pVtab[0][1];
pFun(); //B1::bf1();
cout << " [2] ";
cout << pVtab[0][2] << endl;
cout << "[1] = 0x";
cout << (int*)*((int*)(&bb1)+1) <<endl; //B1::ib1
cout << "[2] B1::ib1 = ";
cout << (int)*((int*)(&bb1)+2) <<endl; //B1::ib1
cout << "[3] B1::cb1 = ";
cout << (char)*((int*)(&bb1)+3) << endl; //B1::cb1
cout << "[4] = 0x";
cout << (int*)*((int*)(&bb1)+4) << endl; //NULL
cout << "[5] B::_vptr->" << endl;
pFun = (Fun)pVtab[5][0];
cout << " [0] ";
pFun(); //B1::f();
pFun = (Fun)pVtab[5][1];
cout << " [1] ";
pFun(); //B::Bf();
cout << " [2] ";
cout << "0x" << (Fun)pVtab[5][2] << endl;
cout << "[6] B::ib = ";
cout << (int)*((int*)(&bb1)+6) <<endl; //B::ib
cout << "[7] B::cb = ";
的对比):
GCC 3.4.4
VC++ 2003
[1] : B1::f1()
[1] B1::ib1 : 11
[0] : B1::f()
[4] B::ib : 0
[0] B1::_vptr->
[2] 0
ç[2] B1::ib1 = 11
[5] B::_vptr->
[2] 0x00000000
这里,大家可以自己对比一下。关于细节上,我会在后面一并再说。
的(因为VC++的相对要清楚很多,所以这里只给出VC++<span lang="ZH-CN" times="" new="" roman';="" mso-hansi-font-family:="" 'times="" roman'"="" style="padding: 0px; margin: 0px; font-family: 宋体;">的程序,GCC和GCC [0] : D::f()
[3] : D::f2()
[1] B1::ib1 : 11
[0] : D::f()
[3] : 0
[6] D::id : 100
[0] : D::f()
[9] B::ib : 0
[0] D::B1::_vptr->
[2] D::Df()
ç-4
[4] D::B2::_vptr->
[2] 00000000
该地址取值后是[7] B2::cb2 = 2
[10] = 0x00000000
[1] B::Bf()
[13] B::cb = B
1),除了一些细节上的不同,其大体上的对象布局是一样的。也就是说,先是B1(灰色),而B关于虚函数表,尤其是第一个虚表,GCC的虚表比较清晰和有逻辑性。
都把B分隔符把B的布局分开。GCC中的内存布局有两个地址我有些不是很明白,在其中我用红色标出了。取其内容是-45)GCC中则没有指向B的size这门语言是一门比较复杂的语言,对于程序员来说,我们似乎永远摸不清楚这门语言背着我们在干了什么。需要熟悉这门语言,我们就必需要了解C++这门最难的编程语言。
,Ajax是:haoel@hotmail.com
本文出自 “陈皓的个人专栏” 博客,请务必保留此出处http://haoel.blog.51cto.com/313033/124561
0 0
- C++对象的内存布局(下)
- C++对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)(转)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- C++ 对象的内存布局(下)
- Codeforces Beta Round #17 C. Balance (字符串计数 dp)
- 模板匹配(基于形状模板)check_soft_cheese例程
- 配置LCD背光和LED及调试方法
- 教你如何迅速秒杀掉:99%的海量数据处理面试题
- ThinkPHP 控制器调试与Trace信息 模版替换变量的修改 开启了日志记录
- C++对象的内存布局下
- 直接拿来用!最火的Android开源项目(完结篇)
- Web攻防系列教程之 PHP + Mysql注入攻防实战
- 跟我一起写 Makefile(作者陈皓)
- Sphider 的应用和php源码分析
- WinForm程序中两份mdf文件问题的解决(转载 )
- hdu 4893 线段树
- 机器学习第二篇(stanford大学公开课学习笔记) —局部加权回归
- 立即调用的函数表达式