创建对象的过程
1.分配内存空间
2.初始化成员变量
3.调用构造方法
1. 分配内存空间(A a 和 new A的不同)
对于全局对象,静态对象以及分配在栈区域内的对象,对它们的内存分配是在编译阶段就完成了,
而对于分配在堆区域内的对象,它们的分配是在程序运行阶段完成的。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
内存空间的分配过程中需要确定分配空间的大小,即类对象的大小,这个问题是编译器根据类数据成员来进行分配。
是否有足够的内存空间来满足分配,对于不同的情况我们需要具体问题具体分析:全局对象和静态对象。编译器会为他们划分一个独立的段(全局段)为他们分配足够的空间,一般不会涉及到内存空间不够的问题。分配在栈区域的对象。栈区域的大小由编译器的设置决定,不管具体的设置怎样,总归它是有一个具体的值,所以栈空间是有限的,在栈区域内同时分配超过空间大小的对象会导致栈区域溢出,由于栈区域的分配是在编译阶段完成的,所以在栈区域溢出的时候会抛出编译阶段的异常。分配在堆区域的对象。堆内存空间的分配是在运行是进行的,由于堆空间也是有限的,在栈区域内试图同时分配大量的对象会导致分配失败,通常情况会抛出运行时异常或者返回一个没有意义的值(通常是0)。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2.初始化成员变量(初始化 和 赋值)
初始化(Initialization)---------初始化列表实现
这一阶段是对象创建过程中最神秘的一个阶段,也是最容易被忽视的一个阶段。要想知道这一阶段具体完成那些任务,关键是要区分两个容易混淆的概念:初始化 (Initialization)和赋值(Assignment)。初始化早于赋值,它是随着对象的诞生一起进行的。而赋值是在对象诞生以后又给予它一个新的值。这里我想到了一个很好的例子:任何一个在医院诞生的婴儿,在它诞生的同时医院会给它一个标识,以防止和其他的婴儿混淆,这个标识通常是婴儿母亲所在床铺的编号,医院给婴儿一个标识的过程可以看作是初始化。当然当婴儿的父母拿到他们会为他们起个名字,起名字的过程就可以看作是赋值。经过初始化和赋值后,其他人就可以通过名字来标识他们的身份了。区分了这两个概念后,我们再转到对对象初始化的分析上。对类对象的初始化,实际上是对类对象内的所有数据成员进行初始化。C++已经为我们提供了对类对象进行初始化的能力,我们可以通过实现构造函数的初始化列表(memberinitialization list)来实现。
初始化列表先于构造函数体内的代码执行;
赋值(Assignment)--------------构造函数函数体内赋值实现
对象经过初始化以后,我们仍然可以对其进行赋值。我们可以通过构造函数的实现体(即构造函数中由"{}"包裹的部分)来实现。
由以上的分析可以看出,构造函数实现了对象的初始化和赋值两个过程:对象的初始化是通过初始化列表来完成,而对象的赋值则才是通过构造函数,或者更准确的说应该是构造函数的实现体。
3.调用构造函数
构造函数的使用
•构造函数重载
–构造函数也是函数,拥有重载的特征
–重载的构造函数在构造对象时根据参数自动选择
•构造函数可以使用默认参数
–构造函数也拥有函数参数默认值的特性
–使用默认值可以减少构造函数的个数
•构造函数的初始化列表
–初始化列表可以让构造函数在被调用之前进行初始化工作
–如果类的成员变量是const或引用类型,必须使用初始化列表初始化
注意:在什么情况下必须使用初始化列表来初始化成员变量而不能使用构造函数赋值来实现?
当类的成员变量是const 或者 引用类型时,必须使用初始化列表进行初始化,原因是:
1. const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类的声明中初始化const数据成员,因为类的对象没被创建时,编译器不知道const数据成员的值是什么。
2. const数据成员的初始化只能在类的构造函数的初始化列表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现,或者static cosnt。
3. 引用的指向只能初始化,不能修改其指向,赋值过程是在修改其指向,其实这就是赋值和初始化的本质区别
总结: 1 . 对象的创建时先分配对象的存储,然后调用构造函数(调用代码段的构造函数并传递刚才开辟的内存空间this指针给该函数),有初始化列表的先初始化列表然后再执行构造函数中的函数体复制操作
2. 成员变量里面有引用类型的变量 或者 是const常量类型的变量 那就必须要使用初始化列表来初始化成员变量。