复制构造函数:
允许所创建的对象是另一个对象的精确副本。如果数据成员是对象,初始化意味着调用它们的复制构造函数。
复制构造函数采用源对象的所有数据字段。与其他构造函数类似,他没有返回值。在这个构造函数内部,应该复制源对象所有的数据字段。在编写复制构造函数时,需要注意浅复制和深复制的问题。
何时调用复制(拷贝)构造函数
C++中传递函数参数的默认方式是值传递,这意味着函数或者方法接收某个值或者对象的副本。因此,无论什么时候给函数或者方法传递一个对象,编译器都会调用新对象的复制构造函数进行初始化。
显式调用复制构造函数,从而将某个对象作为另一个对象的精确副本。
按引用传递对象
当向函数或方法传递对象时,为了避免复制对象,可以让函数或者方法采用对象的引用做参数。当不需要改变原始对象时,可以将对象声明为const。
!!!为了提高性能,最好按const引用传递而不是值传递。
返回数据成员的引用存在风险,因为只有对象“存在”时引用才有效。一旦对象被销毁,引用就失效。然而有时候返回数据成员的引用是合理的。
西安是默认或者删除复制构造函数(仅限于C++11)
可以采用下面的办法将编译器生成的复制构造函数设为默认或者删除
如:
SpreadsheetCell(const SpreadsheetCell& src)= defaoult;
或者
SpreadsheetCell(const SpreadsheetCell& src) = delete;
初始化列表构造函数(仅限于C++11)
类内成员初始化器(仅限于C++11)
C++11允许在定义类的时候直接初始化成员变量。例如:
#include<string>
Class MyClass
{
protected:
Int mInt = 1;
std::string mStr = “test”;
};
在C++11之前,只有在构造函数体或ctor-initializer中才能初始化mInt和mStr,如下:
#include<string>
Class MyClass
{
public:
MyClass():mInt(1),mStr(“test”){}
protected:
Int mInt;
std::string mStr;
};
在C++11之前,只有static const 整型成员变量才能在类定义中初始化,例如:
#include<string>
Class MyClass
{
protected:
static const int kI1 = 1; //ok
static const std::string kStr = “test”;//Error
static int sI2 = 2; //Error:not const
const int kI3 = 3; //Error;not static
};
委托构造函数(仅限于C++11)
委托构造函数允许构造函数调用同一个类的其他构造函数。但是这个调用不能放在构造函数体内,而必须放在构造函数初始化器中。例如:
SpreadsheetCell::SpreadsheetCell(const string& initiaValue):SpreadsheetCell(stringToDouble(initiaValue))
{}
当调用采用字符串做参数的构造函数(委托构造函数)的时候,首先将调用委托给目标,也就是采用double做参数的构造函数,当目标构造函数返回时,在执行委托构造函数。
当使用委托构造函数时,要注意避免出现构造函数的递归。例如:
class MyClass
{
MyClass(char c):MyClass(1.2){}
MyClass(double d):MyClass(‘m’){}
};
第一个构造函数委托第二个构造函数,第二个构造函数委托第一个。C++标准没有定义代码这种行为,这取决于编译器。
编译器为没各类自动生成没有参数的构造函数以及复制构造函数。我们可以自己定义构造函数取代这些系统默认的构造函数。
注意默认构造函数和赋值构造函数之间缺少对称,如果没有显式定义一个复制构造函数编译器就会自动生成一个。另一方面,只要定义了任何一个构造函数,编译器就不会生成默认构造函数。
对象赋值
在C++中可以将一个对象的值付给另一个对象。
需要区别的是“复制”和“赋值”,在C++中“复制”只在初始化对象时发生。如果一个已经具有值的对象被改写,则更精确的术语是“赋值”。在C++中,左右的类提供执行赋值的方法,这个方法称为赋值运算符,其名称为operator=,实际上是为类重载了“=”运算符。在重载赋值运算符时,需要非常注意浅赋值和深赋值。赋值运算符与复制构造函数类似,采用了源对象的const引用。赋值运算符返回对象的引用,原因是赋值可以连续使用。赋值运算符不应该阻止自赋值。所有的赋值运算符都返回*this。