您的位置:首页 > 编程语言 > C语言/C++

c++对象模型

2015-11-21 10:09 357 查看
最近看了本 《c++ 对象模型》的书,收益良多。讲了c++对象中成员的分布,虚函数表等。

先看图

类的层次结构



dev类等成员分布



下面是代码,获取成员数据都是通过内存偏移,所以即使是父类的私有方法获成员,都可以访问到,只能说指针太强大了

typedef void(*Fun)(void);   //void类型的函数指针 //适用于无实例对象,例如全局函数等

// ------------------------------------------------ test1 -------------------------
class Tmp
{
public:
short a;
int b;
double c;
};

class Base
{
public:
Base():base1Num(123) { cout << "Base::Base" << endl; }
virtual ~Base() { cout << "Base::~Base" << endl; }
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
void ooo(){ cout << "Base::ooo" << endl; }
void ppp(){ cout << "Base::ppp" << endl; }

private:
virtual void j() { cout << "Base::j" << endl; }
int base1Num;
};

class Base2
{
public:
Base2():base2Num(456) { cout << "Base2::Base2" << endl; }
virtual ~Base2() { cout << "Base2::~Base2" << endl; }
virtual void x() { cout << "Base2::x" << endl; }
virtual void y() { cout << "Base2::y" << endl; }
void rrr() { cout << "Base2::rrr" << endl; }
void sss() { cout << "Base2::sss" << endl; }

private:
virtual void z() { cout << "Base2::z" << endl; }
int base2Num;
};

class dev : public Base , public Base2
{
public:
virtual void f() { cout << "dev::f" << endl; }
virtual void k() { cout << "dev::k" << endl; }
virtual void z() { cout << "dev::z" << endl; }

public:
int num;
char* str;
dev* child;
Tmp tmp;
//double price; //加了个8个字节的double,字节对齐时会占用更多字节,对象大小增大
};

void testVirtualTable()
{
//Base b1;
//b1.j();            //compile error

dev d;
d.num = 100;
d.str = "hello world";
//d.child = new dev;
//d.child->num = 500;

d.tmp.a = 31;
d.tmp.b = 777;
d.tmp.c = 888;
//d.f();             //compile error

cout << "虚函数表地址:" << (int*)(&d) << endl;
cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&d) << endl;
printf("\n");

//通过函数指针访问到私有的j(), j()对于对象来讲本来是不可见的,指针太强大
Fun pFun2 = nullptr;
//第一个虚函数表指针指向
//pFun2 = (Fun)*((int*)*(int*)(&d) + 0); //Base::~Base //析构不能调
//pFun2();
pFun2 = (Fun)*((int*)*(int*)(&d) + 1); //dev::f //dev重写Base的f
pFun2();
pFun2 = (Fun)*((int*)*(int*)(&d) + 2); //Base::g
pFun2();
pFun2 = (Fun)*((int*)*(int*)(&d) + 3); //Base::h
pFun2();
pFun2 = (Fun)*((int*)*(int*)(&d) + 4); //Base::j
pFun2();
pFun2 = (Fun)*((int*)*(int*)(&d) + 5); //dev::k
pFun2();
//Base base1Num的存储偏移在虚函数表指针的下4个字节
int base1Num = (int)*((int*)(&d) + 1);
printf("--- base1Num:%d\n", base1Num); //123
printf("\n");

//第二个虚函数表指针指向
//pFun2 = (Fun)*((int*)*((int*)(&d) + 1) + 0);  //Base2::~Base2 //析构不能调
//pFun2();
pFun2 = (Fun)*((int*)*((int*)(&d) + 2) + 1);//Base2::y
pFun2();
pFun2 = (Fun)*((int*)*((int*)(&d) + 2) + 2); //Base2::y
pFun2();
pFun2 = (Fun)*((int*)*((int*)(&d) + 2) + 3); //dev::z //dev重写Base2的z
pFun2();
//Base2 base2Num的存储偏移在虚函数表指针的下4个字节
int base2Num = (int)*((int*)(&d) + 3);
printf("--- base2Num:%d\n", base2Num); //456
printf("\n");

//通过地址获取成员变量
int num = (int)*((int*)(&d) + 4);
char* str = (char*)*((int*)(&d) + 5);
printf("--- dev.num:%d\n", num);
printf("--- dev.str:%s\n", str);
printf("\n");

//(base vtp + base1num + base2 vtp + base2num + dev::num + dev::str + dev::dev*) * 4 = 28
//printf("--- dev size : %d\n", sizeof(dev)); //28
//如果 dev 加多个 double 型成员,因为字节对齐是更具最大元素来对界,会得到sizeof为40,参考ByteAlign.cpp;

printf("--- Tmp size : %d\n", sizeof(Tmp));
printf("--- dev size : %d\n", sizeof(dev));

printf("--- str:0x%x\n", str);
Tmp* tmp = (Tmp*)&(*((int*)(&d) + 7));
printf("--- tmp:0x%x\n", tmp);
printf("--- tmp.b:%d\n", tmp->b);

short tmpA = (short)*((int*)(&d) + 7);
printf("--- tmpA:%d\n", (int)tmpA);
int tmpB = (int)*((int*)(&d) + 8);
printf("--- tmpB:%d\n", tmpB);
int tmpC = (int)*((int*)(&d) + 9);
printf("--- tmpC:%d\n", tmp->c);

//dev* child = (dev*)*((int*)(&d) + 4);
//printf("--- child num:%d\n", child->num);

//Base* b2 = new dev();
////b2->k();           //compile error,父类指针无法call子类特有的虚函数

////通过函数指针访问到子类特有的虚函数k(), 指针太强大
//Fun pFun3 = (Fun)*((int*)*(int*)b2 + 4);
//pFun3();
}


运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: