c++程序的内存格局通常分为四个区:
- 全局数据区
data area
,存放全局变量,静态数据和常量; - 代码区
code area
,所有类成员函数和非成员函数; - 栈区
satck area
,为了运行函数而分配的局部变量,函数参数,返回数据,返回地址都存放在栈区; - 堆区
heap area
,即自由存储区。
对于非静态成员变量,我们是在类的实例化过程中(构造对象)才在栈区或者堆区为其分配内存,是为每个对象生成一个拷贝,所以它是属于对象的。
每个对象所占用的存储空间只是该对象的数据部分(虚函数指针和虚基类指针也属于数据部分)所占用的存储空间,而不包括函数代码所占用的存储空间。在C++类对象模型中,类的所有普通成员函数都被放在一个特殊的位置,所有这个类的对象都共用这份成员函数。
虚函数:子类在初始化时会复制父类的虚函数表,如果子类中有同名函数,则会覆盖复制过来的虚函数表,而且当子类对象通过父类指针调用虚函数时,会用虚函数调用子类自己的函数产生多态。调用普通函数不会经过虚函数表,是静态绑定的(在编译期便决定了调用地址偏移量)
虽然调用不同对象的成员函数时都是执行同一段函数代码,但是执行结果一般是不相同的。不同的对象使用的是同一个函数代码段,它怎么能够分别对不同对象中的数据进行操作呢?原来C++为此专门设立了一个名为this的指针,用来指向不同的对象。
静态成员函数和非静态成员函数都是在类的定义时放在内存的代码区,因而可以说它们都是属于类的;
但是类为什么只能直接调用静态类成员函数,而非静态类成员函数(即使函数没有参数)只能类对象才能调用呢?
原因是因为类的非静态类成员函数其实都内含了一个指向类对象的指针型参数(即
this
指针,因而只有类对象才能调用)
需要说明,不论成员函数在类内定义还是在类外定义,成员函数的代码段都用同一种方式存储。不要将成员函数的这种存储方式和inline
(内联)函数的概念混淆。
不要误以为用inline
声明(或默认为inline
)的成员函数,其代码段占用对象的存储空间,而不用inline
声明的成员函数,其代码段不占用对象的存储空间。不论是否用inline
声明(或默认为inline
),成员函数的代码段都不占用对象的存储空间。
用inline
声明的作用是在调用该函数时,将函数的代码段复制插人到函数调用点,而若不用inline
声明,在调用该函数时,流程转去函数代码段的入口地址,在执行完该函数代码段后,流程返回函数调用点。
码段的入口地址,在执行完该函数代码段后,流程返回函数调用点。
inline
与成员函数是否占用对象的存储空间无关,它们不属于同一个问題,不应搞混。