1.说明
类的6个默认成员函数:
如果一个类中什么成员都没有,则称为空类。
而任何一个类,在编写者自己不去实现的情况下,都会自动生成以下6个默认成员函数(前四个是重点):
1.构造函数,主要完成初始化工作(不是开空间创建对象),类似数据结构中常写的init函数。
2.析构函数,主要完成清理工作,类似数据结构中常写的destroy函数。
3.拷贝构造函数,使用同类对象初始化创建对象。
4.赋值重载,主要是把一个对象的值赋给另一个对象。
5&6.普通对象和const对象取地址,这两个很少会自己实现。
1.1构造函数:
是特殊成员函数,虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。
构造函数不是常规的成员函数,调用方式有差别。
构造函数的存在意义是保证对象定义后就被初始化,防止忘记初始化等。
- 构造函数必须是public属性的,否则创建对象时无法调用。
- 构造函数的调用是强制性的:一旦在类中定义了构造函数,那么创建对象时就必须调用,不调用是错误的。
- 构造函数的函数名与类名相同,参数列表没有规定,按需使用。
- 构造函数无返回值,也不是void,不用写任何返回类型。
- 对象实例化时编译器自动调用对应的构造函数,且在对象的生命周期内只调用一次。
- 构造函数可以重载,也就是说可以有多种初始化方式。
- 若有多个重载的构造函数,则创建对象时提供的实参必须与其中一个构造函数匹配,反过来说,创建对象时只有一个构造函数会被调用。
- 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参无内容的默认构造函数,一旦用户显式定义,编译器将不再生成。
- 无参构造函数、全缺省构造函数、用户未写而由编译器默认生成的构造函数,这类不传参就可以调用的构造函数,都可以认为是默认构造函数。
- 默认构造函数只能有一个。
一般建议使用全缺省的默认构造函数,且每个类都提供一个。虽然在语法上可以同时存在全缺省和无参的,但若有对象定义或调用就会报错。
(另,C中没有拷贝构造,所以C可以安全地直接传结构体,而C++中,可以认为自定义类型传值传参等同于拷贝构造:都是用同类型对象来初始化)
注意:默认构造函数只会为class,struct等自定义类型成员调用,而对int,char等内置类型成员不做处理。
c++11中针对内置类型成员不默认初始化这一缺陷打了个补丁:
内置类型的成员变量在类中声明时可以给缺省值。
当然,实际操作中大部分时候是需要自己去写构造函数,而不是只靠默认的。
1.1.1构造体函数赋值
创建对象时,编译器会调用构造函数,给对象中各个成员变量一个合适的初始值。
class Date{
public:
Date(int year, int month, int day){
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
虽然前述构造函数调用后,对象中已有初始值,但不能称之为对于对象中成员变量的初始化。
构造函数体中的语句只能将其称为赋初值,而不能称作初始化。
因为初始化只能进行一次,而构造函数体内可以多次赋值。
1.1.2初始化列表
以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
class Date{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
, _day(day)
{
}
private:
int _year;
int _month;
int _day;
};
初始化列表特性:
- 初始化列表能只能初始化一次,多次初始化会报错
-编译器也允许构造函数赋初值和初始化列表初始化混用。混用时初始化列表初始化和构造函数赋初值不冲突,但混用时初始化列表初始化还是要遵循只能初始化一次成员变量的原则。 - const成员变量、引用成员变量、没有默认构造函数的自定义类型成员,必须使用初始化列表来进行初始化。
原因:
-初始化列表是对象的成员变量定义的地方。
-对象的内置类型成员变量在初始化列表定义时并不要求必须初始化,因此既可以在初始化列表进行初始化,也可以在构造函数体内初始化。
-const成员变量、引用成员变量、没有默认构造函数的自定义类型成员变量不能先定义再初始化——它们在初始化列表内定义,且必须在定义时就初始化。
class A{
public:
A(int a)
:_a(a)
{
}
private:
int _a;
};
class B
{
public:
B(int a, int ref)
:_aobj(a)