关闭

c++对象模型

标签: c++对象模型虚函数表
365人阅读 评论(0) 收藏 举报
分类:

最近看了本 《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();
}


运行结果





0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

[读书笔记] 深入探索C++对象模型-第一章《关于对象》

最新在看深入探索C++对象模型(Inside C++ object model),看的同时针对一些之前没有留意或者理解不深的内容整理一下读书笔记,方便之后复习,也希望可以帮助到有同样疑惑的人。 下面是...
  • beyongwang
  • beyongwang
  • 2016-08-21 21:14
  • 583

C++对象模型之简述C++对象的内存布局

在C++中,有两种类的成员变量:static和非static,有三种成员函数:static、非static和virtual。那么,它们如何影响C++的对象在内存中的分布呢? 当存在继承的情况下,其内存...
  • ljianhui
  • ljianhui
  • 2015-05-22 02:28
  • 9714

《深入理解C++对象模型》读书笔记(一)

1、           C++类对象模型的中包括非静态成员变量和虚函数表指针,其他静态成员变量和成员函数均放在对象模型之外,所有的对象示例均可以共同使用。如此可以节省访问的时间和空间效率。...
  • zhiren2011
  • zhiren2011
  • 2015-07-31 10:49
  • 1066

C++对象的内存模型

转载自:http://c.biancheng.net/cpp/biancheng/view/2995.html点击打开链接 当对象被创建时,编译器会为每个对象分配内存空间,包括成员变量和成员函数。 ...
  • chengonghao
  • chengonghao
  • 2016-04-01 09:25
  • 1296

深度探索c++对象模型

所谓知己知彼,百战不殆。只有深入了解了c++对象的内存布局,我们才能更熟练运用c++这门语言。 运行环境vs2013一单继承和多继承的结合class C { public: C() :c(1...
  • db199410
  • db199410
  • 2016-06-16 17:40
  • 371

c++对象内存模型【内存布局】

#类中的元素 0. 成员变量   1. 成员函数   2. 静态成员变量   3. 静态成员函数   4. 虚函数   5. 纯虚...
  • IT_YUAN
  • IT_YUAN
  • 2014-04-28 16:30
  • 11840

C++面向对象模型初探

C++中的class从面向对象理论出发,将变量(属性)和函数(方法)集中定义在一起,用于描述现实世界中的类。从计算机的角度,程序依然由数据段和代码段构成。 C++编译器如何完成面向对象理论到计算机程序...
  • lishuhuakai
  • lishuhuakai
  • 2015-05-23 00:32
  • 865

C++对象模型浅析

VTable 虚表 虚表的内存分布 一个简单的包含虚函数的类的声明 class A { public: virtual void v_a(){} virtual ~A...
  • whn_arthur
  • whn_arthur
  • 2016-02-23 17:29
  • 365

详细介绍C++中的类对象内存模型

内存模型描述的是程序中各变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节.不同平台间的处理器架构将直接影响内存模型的结构. 首先介绍一...
  • ywcpig
  • ywcpig
  • 2016-09-12 23:14
  • 2072

《深入理解c++对象内存模型》读书笔记

this指针的由来,虚函数的编译,多态的本质
  • FANYIYAO980404514
  • FANYIYAO980404514
  • 2015-03-29 22:05
  • 1182
    博客专栏
    个人资料
    • 访问:482820次
    • 积分:7115
    • 等级:
    • 排名:第3725名
    • 原创:243篇
    • 转载:27篇
    • 译文:0篇
    • 评论:136条
    座右铭

    忠于内心,修炼坚持

    --Wilker_Yun