深度探索C++对象模型-第一章

关于对象

一 C++封装成本

C++用类去定义对象时,系统会为每一个对象分配存储空间。每个对象所占用的存储空间只是该对象的数据部分(虚函数指针和虚基类指针也属于数据部分)所占用的存储空间,而不包括函数代码所占用的存储空间。

C++程序的内存格局通常分为四个区:全局数据区(data area),代码区(code area),栈区(stack area),堆区(heap area)(即自由存储区)。

全局数据区存放全局变量,静态数据和常量

所有类成员函数和非成员函数代码存放在代码区;

为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区;

余下的空间都被称为堆区。

根据这个解释,我们可以得知在类的定义时,类成员函数是被放在代码区,而类的静态成员变量在类定义时就已经在全局数据区分配了内存,因而它是属于类的。对于非静态成员变量,我们是在类的实例化过程中(构造对象)才在栈区或者堆区为其分配内存,是为每个对象生成一个拷贝,所以它是属于对象的。

需要注意的是,虽然调用不同对象的成员函数时都是执行同一段函数代码,但是执行结果一般是不相同的。不同的对象使用的是同一个函数代码段,它怎么能够分别对不同对象中的数据进行操作呢?原来C++为此专门设立了一个名为this的指针,用来指向不同的对象。

不论成员函数在类内定义还是在类外定义,成员函数的代码段都用同一种方式存储。

C++的成本主要是由于虚拟导致的:

  • 虚函数:执行期绑定
  • 虚基类:实现多次出现在继承体系中的基类,有一个单一而被共享的实例。

参考:C++成员函数在内存中的存储方式

二 struct和class一些不同

1 C++中处于同一个访问部分(privateprotectedpublic)的数据,必定保证以其声明顺序出现在内存中,然而被放置在多个访问部分的不同数据,排列顺序就不一定了。

2 当传递一个复杂的类对象的全部或者部分到一个C函数中去,struct声明可以将数据封装起来,并且保证和C语言兼用的内存布局,这只能在组合情况下才能实现。

struct Acore{};
class A{
private:
    Acore c;
};

二 多态实现原理

多态实现有两个必要条件:

  • 基类包含虚函数
  • 通过指针和引用调用

当程序中以对象进行赋值,将派生类对象的值赋给基类的时候,会产生截断,基类的对象只能接受派生类中基类的部分。

class Base{};
class Derived:pubclic Base{};
Base b;
Derived d;
b = d;  //产生截断

对于指针和引用来说(本质上引用是通过指针来实现的),不管指向什么数据类型,指针本身的内存大小是固定的,不同的类型只是对应着不同的解释方式。所以基类的指针指向的内存区域大小就是基类的大小,而派生类指向的内存区域大小就是派生类的大小。

class Base{};   //假设大小为16
class Derived:pubclic Base{};   //假设大小为24(16+8)
Base b;
Derived d;
Base *pb = d;   //pb指向的内存区域仅仅包括d中基类的部分
Derived *pd = d;//pd指向的内存区域包括d所有部分

所以通过对象是没有办法实现多态的,而通过指针或者引用的间接方式,通过虚函数的虚函数表,可以在运行期决定执行的具体函数内容。

PS:RTTI

C++ RTTI(运行阶段类型识别)

猜你喜欢

转载自blog.csdn.net/u012630961/article/details/80393516