我们初学C++时可能会对类的构造函数,复制构造函数,析构函数有点疑问。整理如下(个人见解,如有错误,还望指正。):
1.构造函数
根据构造函数的定义知它的作用是初始化类的数据成员或内嵌类的对象,所以它的参数表就应该是它要初始化的对象类型。构造函数分三类:默认构造函数、构造函数、委托构造函数。
默认构造函数
默认构造函数没有返回值,没有参数表,没有函数体,如果类内没有显式的定义构造函数,系统会自动生成默认构造函数,如果已经定义了构造函数,但仍需要默认构造函数,可以在默认构造函数参数表后加default:
Point() = default;
提示:即使已经定义了构造函数,最好也定义一个默认构造函数,以备不时之需。
构造函数
普通的构造函数有两种形式:带有初始化列表、不带初始化列表两种,一般情况下这两种没多大区别,但有几种特殊情况必须使用带初始化列表的形式:如果要初始化的成员是引用、const类型或者属于某种为提供默认构造函数的类类型时,必须通过构造函数的初始值列表进行初始化。对于这个:
class Point
{ public:
Point(int a,int b):x(a),y(b) {}
private:
int x,y;
};
如果主函数有如下语句:Point p = Point(1,2);既可以看成是强制类型转换,也可以看成构造函数的调用。不仅是类,甚至是内置数据类型,比如int、float、double等,如果有int a = int(3.14); 这样的语句,既可以看成强制类型转换,也可以看成int的构造函数的调用,有人会有疑问:int是数据类型,怎么会有构造函数?我想用Python中的工厂函数来解释比较贴切,形如int()在Python中称为工厂函数,听名字就知道,工厂就是大量生产的意思,就是生产int型数据的工厂。这样好理解了吧。
委托构造函数
委托构造函数并不常用,顾名思义,委托构造函数就是把一个构造函数的任务委托给另一个构造函数。委托构造函数和构造函数一样,有一个初始值列表和函数体比如:
class Point //点类
{ public:
Point(int a,int b):x(a),y(b) {} //带形参的构造函数
Point(): Point(0,0) {} //委托构造函数,默认构造函数委托带有两个int型形参的构造函数初始化数据成员
private:
int x,y;
};
2.复制构造函数
复制构造函数的参数是本类对象的引用,复制构造,顾名思义,就是拿本类的对象初始化本类的另一个对象的喽,形参当然是本类对象的引用啦。类的继承也不例外,派生类的复制构造函数的参数也是派生类对象的引用,根据类型兼容规则,派生类的对象可以初始化基类对象,所以这样是允许的。但基类对象初始化派生类对象却是不安全的,因为派生类包含基类的成员(基类的构造函数、复制构造函数和析构函数除外),所以派生类的范围要大于基类。用一句话来说就是:大的可以初始化小的,但小的不能初始化大的(dynamic_cast类型转换也是这个道理)。
复制构造函数归根结底落脚点还是构造,有木有发现构造函数和复制构造函数长得很像,它们有很多共同之处。所以可以把复制构造函数看成构造函数的一种重载形式,区别就是它们的参数表不同,系统会根据实参的不同类型调用构造函数或者复制构造函数。
3.析构函数
析构函数非常简单,它没有返回值,没有参数表,没有函数体,函数名与类名相同,函数名前需要加一个~以便于默认构造函数区分开来。一般情况下我们不必太在意析构函数,但有一种情况需要注意,就是在实现类的多态性时最好要把基类和派生类的析构函数声明为虚函数,以便在使用动态内存时能正确释放申请的堆空间。