拷贝控制操作
5种特殊的成员函数:拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符、析构函数。
这5种特殊的成员函数用来控制定义一个类对象拷贝、移动、赋值和销毁操作,统称为拷贝控制操作。
拷贝和移动构造函数:定义了当用同类型的另一个对象初始化本对象时的操作。
拷贝和移动赋值运算符:定义了将一个对象赋予同类型的另一个对象时的操作。
析构函数:定义了当此类型对象销毁时的操作。
缺点:我们没有显示定义这些操作函数,系统就会自动为它定义缺失的操作,有时默认定义会导致灾难。
拷贝构造函数
class CExample
{
public:
CExample(){pBuffer=NULL;nSize=0;}
~CExample(){delete[] pBuffer;}
void Init(int n){pBuffer=new char[n];nSize=n;}
public:
char*pBuffer;
int nSize;
CExample(const CExample &RightSides)
{
nSize=RightSides.nSize;
pBuffer=new char[nSize];
memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));
}
};
int main()
{
CExample theObjone;
theObjone.Init(40);
CExample theObjtwo=theObjone;
if(theObjtwo.pBuffer==theObjone.pBuffer)
//没有拷贝构造函数时,系统就会崩溃,无限复制,并修改了原对象。
cout<<"你"<<endl;
return 0;
}
拷贝构造函数的定义
class Foo
{
public:
Foo(); //默认构造函数
Foo(const Foo &f)//拷贝构造函数
}
/*
Foo(const Foo& f):第一个参数f必须是一个引用类型。
假如我们定义一个类没有拷贝构造函数,如: */
class Foo
{
public:
Foo(); //默认构造函数
//Foo(int n); //即便定义重载构造函数,编译器仍会为我们自动合成一个拷贝构造函数。
}
那么编译器会为我们隐式地定义一个拷贝构造函数Foo(const Foo& )。
拷贝构造函数的特点:
1.阻止拷贝该类类型的对象。
2.编译器从给定对象中依次将每个非静态成员拷贝到正在创建的对象中。
拷贝方式:
(1)类类型的成员:使用其拷贝构造函数来拷贝。
(2)内置类型的成员直接拷贝。
class Sales_data
{
public:
Sales_data(const Sales_data&);
private:
string bookNo;
int units_sold=0;
double revenue=0.0;
};
//与Sales_data的合成的拷贝构造函数等价
Sales_data::Sales_data(const Sales_data &orig):
bookNo(orig.bookNo),//使用string的拷贝构造函数
units_sol(orig.units_sold),//拷贝orig.units_sold
revenus(orig.revenue)//拷贝orig.revenue
{ }
拷贝初始化
直接初始化:要求编译器使用普通的函数匹配选择与我们提供的参数最匹配的构造函数,即普通构造函数或重载构造函数。
拷贝初始化:要求编译器将右侧运算对象拷贝到正在创建的对象中。
string dots(10,’.’);//直接初始化
string s(dots);//直接初始化
string s2=dots;//拷贝初始化
string null_book=”9-999-99999-9”;//拷贝初始化
string nines=string(100,’9’);
拷贝初始化不仅在‘=’运算符定义变量时会发生,在以下情况也会发生:
1.将一个对象作为实参传递给一个非引用类型的形参
2.从一个返回类型为非引用类型的函数返回一个对象
3.用花括号列表初始化一个数组中的元素或一个聚合类中的成员
4.容器拷贝,
string word;
while(cin>>word)
container.push_back(word);
在容器尾部创建的新元素值是word的一个拷贝。
直接初始化,不是拷贝
c.emplace_back(“978-0590353403”,25,15.99);
拷贝赋值运算符
Sales_data trans,accum;
trans=accum;//使用Sales_data的拷贝赋值运算符
重载赋值运算符
拷贝赋值运算符
class Foo
{
public:
Foo& operator=(const Foo&);//赋值运算符
};
合成拷贝赋值运算符
作用:
1.用来禁止该类类型对象的赋值
2.将右侧运算符对象的每一个非static成员赋予左侧运算对象的对应成员。
等价于
Sales_data& Sales_data::operator=(const Sales_data &rhs)
{
bookNo=rhs.bookNo; //调用string::operator=
units_sold=rhs.units_sold; //使用内置的int赋值
revenue=rhs.revenue; //使用内置的double赋值
return *this; //返回一个此对象的引用
}
--