之前一直理解的构造函数的参数里没有this指针,因为此时对象还没生成,其他非static成员函数才有this指针,因为当它们被调用时对象已经生成了。然而这样理解是错误的,构造函数参数里也是有this指针的,但这个this指针只是指向了一个内存地址,这个内存地址还并不代表一个类对象,当构造函数完成后,这个地址有足够的信息后才表示这是一个类对象。
#include <stdio.h>
#include <stdlib.h>
#include <string>
struct Test
{
char a;
int b;
int c;
std::string str;
};
class CBase
{
public:
CBase(): mValue(100)
{
printf("constructor, mValue = %d\n", mValue);
}
~CBase()
{
printf("destructor\n");
}
int getValue()const
{
return mValue;
}
private:
int mValue;
Test mData;
};
int main()
{
printf("sizeof(CBase) = %lu\n", sizeof(CBase));
CBase *instance = new CBase();
int value = instance->getValue();
delete instance;
return 0;
}
在 new 那行添加断点,如:
从这里应该可以看出,在构造函数之前,this指针已经分配了,指向的内存为0x602010,那我们可以看下这个内存里有什么,如:
此时内存里都是0,这里的x/8xw 表示打印8个单元内容,每个单元4个字节,以16进制显示,因为sizeof(CBase) = 32,所以这里打印了 32 个字节的内容。再单步往下执行,会调用 struct Test结构体的构造函数,及进行到初始化列表,如:
到这里已经进到构造函数里面了,其成员数据已经初始化完成,我们可以看到此时this指向的内存的内容发生了变化,this指向的前4个字节变成了 0x00000064,其10进制就是:100,就是初始化列表里的 mValue(100),最后两个应该是std::string 变量里的值(std::string 的内存结构这里不详述,有兴趣的同学可以去研究一下)。然后非static成员函数调用时,此时this指针指向的内容就是构造函数构造出来的内容,如:
所以,我们可以得出,构造函数里的this指针指向的就是一块空内存(内容可能也是随机的),而非static成员函数里的this指针,其内存里已经有了初始化值(通过初始化列表或构造函数里赋值)。我们这里是用到了 new 操作符,那我们可以看一下 new 操作符是怎样工作的,这样也可以验证我们的结论。这里找到的文档为 microsoft 的文档:new 操作符如何工作,截取一段内容:
How new
works
The new-expression
(the expression containing the new
operator) does three things:
-
Locates and reserves storage for the object or objects to be allocated. When this stage is complete, the correct amount of storage is allocated, but it's not yet an object.
-
Initializes the object(s). Once initialization is complete, enough information is present for the allocated storage to be an object.
-
Returns a pointer to the object(s) of a pointer type derived from
new-type-id
ortype-id
. The program uses this pointer to access the newly allocated object.
The new
operator invokes the function operator new
. For arrays of any type, and for objects that aren't class
, struct
, or union
types, a global function, ::operator new
, is called to allocate storage. Class-type objects can define their own operator new
static member function on a per-class basis.
When the compiler encounters the new
operator to allocate an object of type T
, it issues a call to T::operator new( sizeof(T) )
or, if no user-defined operator new
is defined, ::operator new( sizeof(T) )
. It's how the new
operator can allocate the correct amount of memory for the object.
文档里说明,第一步完成时,此时所分配的内存并未表示是一个 “对象”,当第2步完成后,此时的内存才表示是一个“对象”。