编译器默认生成的函数

拷贝控制函数包括:拷贝构造函数、拷贝赋值函数、移动构造函数、移动赋值函数、析构函数。

编译器默认生成的函数:默认构造函数,拷贝构造函数,拷贝赋值函数,析构函数,取地址符,取地址符const

1.构造函数

如果我们没有定义任何构造函数,编译器会为我们生成一个默认的构造函数。

如果定义了,则没有默认构造函数,即不能以Class item来定义对象了。

因此,不管有没有定义构造函数,最好自己定义下默认构造函数。


2.拷贝构造函数

class Foo{
public:
	Foo(){}
	Foo(const Foo&);  //拷贝构造函数
};
有以下几点说明:

1)第一个参数必须是自身的引用类型,而且几乎总是一个const引用。

这里必须是引用的原因是:拷贝构造函数被用来初始化非引用类型参数,如果不是引用类型,就会无限循环。

2)拷贝构造函数一般都会被隐式地使用,因此不应该是explicit的。

关于拷贝初始化与直接初始化:

直接初始化直接调用与实参匹配的构造函数(包括拷贝构造函数),拷贝初始化首先使用指定构造函数创建一个临时对象,然后使用赋值构造函数将那个临时对象复制到正在创建的对象。

如果使用等号初始化一个变量,实际上执行的是拷贝初始化,如果不使用等号,则执行的是直接初始化。拷贝初始化在下面情况下也发生:

1)将一个对象作为实参传给一个非引用类型的形参。

2)从一个返回类型为非引用类型的函数返回一个对象。

3)用花括号列表初始化一个数组中的元素或一个聚合类中的成员。

(聚合类:所有成员都是public;没有定义构造函数;没有类内初始值;没有基类,没有virtual函数。)


3.赋值构造函数

class Foo{
public:
	Foo(){}
	Foo & operator=(const Foo&);  //赋值构造函数
};

有以下几点说明:
1)为了与内置类型一直(a=b=c),返回一个指向其左侧运算对象的引用。

2)参数是const引用


4.析构函数



5.move构造函数(C++11)



6.move赋值构造函数(C++11)





补充:
1.需要析构函数的类也需要拷贝和赋值操作

class HasPtr{
public:
	HasPtr(const string &s = string()) :ps(new string(s)), i(0){}
	~HasPtr(){ delete ps; }
private:
	string *ps;
	int i;
};
例如,上面这个类,需要析构函数来删除ps。如果我们没定义拷贝和赋值操作,默认的拷贝和赋值构造函数会执行下面操作:

#include<iostream>    
#include <string>  
#include <vector>  
using namespace std;


class HasPtr{
public:
	HasPtr(const string &s = string()) :ps(new string(s)), i(0){}
	~HasPtr(){ delete ps; }/*
	HasPtr(const HasPtr &hp){  //默认的拷贝构造函数执行的操作
		ps = hp.ps;
		i = hp.i;
	}*/
private:
	string *ps;
	int i;
};

int main()
{
	HasPtr hp1("test");
	HasPtr hp2(hp1);   //错误:两个对象的ps指向相同的内存,hp2析构时delete会出错。
	return 0;
}

上面出现的问题也就是浅拷贝问题。

浅拷贝:在对象拷贝时,只是对对象中的数据成员进行简单的赋值,如果对象中存在动态成员,即指针,浅拷贝就会让两个指针指向同一个内存,会出现问题。

深拷贝:针对成员变量存在指针的情况,不仅仅是简单的指针赋值,而是重新分配内存空间。

2.需要拷贝操作的类也需要赋值操作,反之亦然

例如,一个类为每个对象分配一个独有的、唯一地序号。


3.使用=default可以显式要求编译器生成默认版本。其中default在类内声明时使用,则隐式地声明为内联函数,如果在类外定义时使用,则不是内联函数。

4.阻止拷贝

1)定义删除的函数

#include<iostream>    
#include <string>  
#include <vector>  
using namespace std;


class NoCopy{
public:
	NoCopy() = default;
	~NoCopy() = default;
	NoCopy(const NoCopy &nc) = delete;  //=delete必须在第一次声明时出现
	NoCopy& operator=(const NoCopy&nc) = delete;
private:
	string *ps;
	int i;
};

int main()
{
	NoCopy hp1();
	NoCopy hp2(hp1);   //错误
	return 0;
}
注意:对应删除了析构函数的类,编译器不允许定义该类型的变量或创建该类的临时对象,可以动态分配这种类型的对象,但是不能释放这些对象。
#include<iostream>    
#include <string>  
#include <vector>  
using namespace std;


class NoCopy{
public:
	NoCopy() = default;
	~NoCopy() = delete;
};

int main()
{
	NoCopy hp1;  //错误
	NoCopy *hp2 = new NoCopy();  //正确
	delete hp2;    //错误
	return 0;
}
当不可能拷贝、赋值或销毁类的成员时,累的默认拷贝控制成员就被定义为删除的。
2)private拷贝控制

将拷贝构造函数和拷贝赋值函数声明为private可以阻止拷贝。


补充:取址运算符和取址运算符const

Empty *operator&();
const Empty*operator&() const;


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值