拷贝构造函数:
构造函数的第一个参数必须是一个引用类型,且任何额外擦数都有默认值。
拷贝构造函数的第一个参数必须是一个引用类型,因为
拷贝构造函数被用来初始化非引用类类型参数。
拷贝初始化:
将右侧运算对象拷贝到正在创建的对象中,如果需要的话还要进行类型转换。
拷贝初始化通常使用拷贝构造函数完成的。
拷贝构造函数在以下的情况会被调用:
1.拷贝初始化(用=定义变量)。
2.将一个对象作为实参传递给非引用类型的参数。
3.一个返回类型为非引用类型的函数返回一个对象。
4.用花括号初始化一个数组中的元素或一个聚合类中的成员
5.初始化标准容器或调用其insert/push操作时,容器会对其元素进行拷贝初始化
拷贝赋值运算符:
拷贝赋值运算符本身是一个重载的赋值运算符,定义为类的成员函数,左侧运算对象绑定到隐含的this参数,而右侧运算对象是所属类类型的,作为函数的参数,函数返回指向其左侧对象的引用。
当对类对象进行赋值时,会使用拷贝赋值运算。
通常情况下,合成的拷贝赋值运算符会将右侧对象的非static成员逐个赋予左侧对象的对应成员,这些赋值操作是由成员类型的拷贝赋值运算来完成的。
若一个类未定义自己的拷贝赋值运算符,编译器就会为其合成拷贝运算符。
#include <iostream>
#include <vector>
using namespace std;
class sales_item
{
public:
sales_item() : units_sold(0), revenue(0.0)
{
cout << "默认构造函数被调用" << endl;
}
sales_item(const std::string &book) :
bookno(book), units_sold(0), revenue(0.0)
{
cout << "构造函数被调用" << endl;
}
//与合成的拷贝构造函数等价的拷贝函数的声明
sales_item(const sales_item &orig);
sales_item& operator=(const sales_item &rhs);
private:
std::string bookno;
unsigned units_sold;
double revenue = 0.0;
};
sales_item::sales_item(const sales_item &orig) :
bookno(orig.bookno), units_sold(orig.units_sold), revenue(orig.revenue)
{
cout << "拷贝构造函数被调用" << endl;
}
sales_item fun(sales_item item)
{
cout << "调用foo:"<<endl;
sales_item temp;//调用默认构造函数
temp = item;//拷贝赋值运算符被调用
//从一个返回类型为非引用类型的函数返回一个对象
return temp;
}
sales_item& sales_item::operator=(const sales_item &rhs)
{
cout << "拷贝赋值运算符被调用" << endl;
bookno = rhs.bookno;//调用string::operator=
units_sold = rhs.units_sold;//使用内置的int赋值
revenue = rhs.revenue;//使用内置的double赋值
return *this;//返回一个队此对象的引用
}
//如果我们不写拷贝构造函数和赋值赋值操作符构造函数的时候,系统会自动会为我们生成;
//但是当一个类里面有数据成员有指针的时候,动态地分配了内存的时候,那就必须自己写了
class foo
{
public:
//用指针p指向动态创建的字符串
foo() :p(new std::string), a(0), b(0){
cout << "foo的默认构造函数被调用了" << endl;
}
foo(const foo& other) :
//通过P指针把字符串拿到,然后构建一个新的字符串,再把p初始化
p(new std::string(*(other.p))), a(other.a), b(other.b)//如何使系统默认的则会写成p(obj.p)
{
cout << "foo的拷贝构造函数被调用" << endl;
}
foo& operator=(const foo &rhs)
{
cout << "foo的赋值操作符被调用" << endl;
p = new std::string;
*p = *(rhs.p);
a = rhs.a;
b = rhs.b;
return *this;
}
private:
std::string *p;
int a;
double b;
};
int main()
{
sales_item ret;//调用默认构造函数
ret = fun(ret);//将一个对象作为实参传递给一个非引用类型的参数
cout << endl;
sales_item a = "9-999-9999-999";//拷贝构造函数,但是编译器会绕过拷贝构造函数
//将sales_item a = "9-999-9999-999"变成sales_item a(9-999-9999-999);
cout <<"数组"<< endl;
sales_item primer_eds[]{
string("2016-04-04"),
string("2016-04-04"),
string("2016-04-04"),
};
cout << "vector:" << endl;
vector<sales_item> svec(5);
cout << endl;
foo x, y;
foo z(x);
x = y;
return 0;
}
拷贝赋值运算符:
#include <iostream>
#include <vector>
using namespace std;
class sales_item
{
public:
sales_item() : units_sold(0), revenue(0.0)
{
cout << "默认构造函数被调用" << endl;
}
sales_item(const std::string &book) :
bookno(book), units_sold(0), revenue(0.0)
{
cout << "构造函数被调用" << endl;
}
//与合成的拷贝构造函数等价的拷贝函数的声明
sales_item(const sales_item &orig);
sales_item& operator=(const sales_item &rhs);
private:
std::string bookno;
unsigned units_sold;
double revenue = 0.0;
};
sales_item::sales_item(const sales_item &orig) :
bookno(orig.bookno), units_sold(orig.units_sold), revenue(orig.revenue)
{
cout << "拷贝构造函数被调用" << endl;
}
sales_item fun(sales_item item)
{
cout << "调用foo:"<<endl;
sales_item temp;//调用默认构造函数
temp = item;//拷贝赋值运算符被调用
//从一个返回类型为非引用类型的函数返回一个对象
return temp;
}
sales_item& sales_item::operator=(const sales_item &rhs)
{
cout << "拷贝赋值运算符被调用" << endl;
bookno = rhs.bookno;//调用string::operator=
units_sold = rhs.units_sold;//使用内置的int赋值
revenue = rhs.revenue;//使用内置的double赋值
return *this;//返回一个队此对象的引用
}
//如果我们不写拷贝构造函数和赋值赋值操作符构造函数的时候,系统会自动会为我们生成;
//但是当一个类里面有数据成员有指针的时候,动态地分配了内存的时候,那就必须自己写了
class foo
{
public:
//用指针p指向动态创建的字符串
foo() :p(new std::string), a(0), b(0){
cout << "foo的默认构造函数被调用了" << endl;
}
foo(const foo& other) :
//通过P指针把字符串拿到,然后构建一个新的字符串,再把p初始化
p(new std::string(*(other.p))), a(other.a), b(other.b)//如何使系统默认的则会写成p(obj.p)
{
cout << "foo的拷贝构造函数被调用" << endl;
}
foo& operator=(const foo &rhs)
{
cout << "foo的赋值操作符被调用" << endl;
p = new std::string;
*p = *(rhs.p);
a = rhs.a;
b = rhs.b;
return *this;
}
private:
std::string *p;
int a;
double b;
};
int main()
{
sales_item ret;//调用默认构造函数
ret = fun(ret);//将一个对象作为实参传递给一个非引用类型的参数
cout << endl;
sales_item a = "9-999-9999-999";//拷贝构造函数,但是编译器会绕过拷贝构造函数
//将sales_item a = "9-999-9999-999"变成sales_item a(9-999-9999-999);
cout <<"数组"<< endl;
sales_item primer_eds[]{
string("2016-04-04"),
string("2016-04-04"),
string("2016-04-04"),
};
cout << "vector:" << endl;
vector<sales_item> svec(5);
cout << endl;
foo x, y;
foo z(x);
x = y;
return 0;
}
赋值运算符和拷贝构造函数的区别与联系?
相同点:都是将一个对象拷贝到另一个中去。
不同点:拷贝构造函数涉及到要新建立一个对象。
#include <iostream>
#include <vector>
using namespace std;
class sales_item
{
public:
sales_item() : units_sold(0), revenue(0.0)
{
cout << "默认构造函数被调用" << endl;
}
sales_item(const sales_item &orig) :
bookno(orig.bookno), units_sold(orig.units_sold), revenue(orig.revenue)
{}
sales_item& operator=(const sales_item &rhs)
{
bookno = rhs.bookno;//调用string::operator=
units_sold = rhs.units_sold;//使用内置的int赋值
revenue = rhs.revenue;//使用内置的int赋值
return *this;//返回一个队此对象的引用
}
private:
int bookno = 1;
int units_sold = 2;
int revenue = 3;
};
int main()
{
sales_item a, b;
sales_item c = b;
a = c;
return 0;
}