C++ Copy Constructor (拷贝构造函数,复制构造函数)

1.什么是Copy Constructor?

 

 

Copy Constructor 是一个特殊的构造函数,一般只有一个参数,这个参数一般是用const修饰的,对自己类的一个引用(reference)。什么时候会用到Copy Constructor?

 

当我们定义一个对象时,它是由另外一个对象来初始化的时候就用到Copy Constructor了。还有就是在一个方法以值作为参数传进去或者一个方法中以值作为返回。

对于我这新手C++,Copy Constructor 用的比较少,真正用到了也不知道,因为一个类缺少 Copy Constructor 时,编译器会自动生成一个。

 

2.赶快来看一个Copy Constructor例子

 

2.1系统默认会提供一个Copy Constructor

 

class People{
private:
	int m_age;
public:
	People(int age):m_age(age){
		cout << "constructor" << endl;
	}

	~People(){
		cout << "destructor" << endl;
	}
	int getAge() const{
		return m_age;
	}
};

一个简单的类,叫People,只有一个属性age

 People p1(18);
    cout << "p1's age " << p1.getAge() << endl;
    People p2(p1);
    cout << "p2's age " << p2.getAge() << endl;

当我们调用上面的代码时的输出结果就是:

 

 

代码工作非常符合我们预期,因为系统会提供一个Copy Constructor,对类里的属性进行简单的赋值工作。

 

2.2自定义的Copy Constructor

 

class People{
private:
    int m_age;
public:
    People(int age):m_age(age){
        cout << "constructor" << endl;
    }
    //copy constructor
    People(const People& p){
        cout << "copy constructor" << endl;
    }

    ~People(){
        cout << "destructor" << endl;
    }
    int getAge() const{
        return m_age;
    }
};
People p1(18);
    cout << "p1's age " << p1.getAge() << endl;
    People p2(p1);
    cout << "p2's age " << p2.getAge() << endl;

这次我们自定义了一个Copy Constructor

还是调用上次的代码,结果:

 

 

看,成功的调用了我们的copy constructor,因为我们的copy constructor 里什么也没做,所以p2的age就是一个未初始化的int值了。

 

2.3还有两种情况会触发调用Copy constructor

 

//作为一个值从函数中返回
People getPeople(){
	People p1(20);
	return p1;//会调用 copy constructor
}
//以值作为参数传入
void setPeople(People p1){//以值传入会调用 copy constructor
	//do nothing
}

void setPeople(People& p1){//以引用传入不会调用 copy constructor
	//do nothing
}

因为调用copy constructor的消耗比较大,所以一般都以引用方式作为函数参数。

 

3. copy constructor 与 assignment operator 的区别

 

 

我们忘记提到的是下面这种写法也会触发copy constructor:

People p1(18);
	cout << "p1's age " << p1.getAge() << endl;
	People p2 = p1;
	cout << "p2's age " << p2.getAge() << endl;

这种写法似乎跟赋值很像。

我们修改People的类,增加重载=操作符。

class People{
private:
	int m_age;
public:
	People(int age):m_age(age){
		cout << "constructor" << endl;
	}

	People(const People& p){
		cout << "copy constructor" << endl;
	}

	People& operator=(const People& p1){
		cout << "assignment operator" << endl;
		m_age = p1.getAge();  
                return *this;  
	}

	~People(){
		cout << "destructor" << endl;
	}
	int getAge() const{
		return m_age;
	}
};
//测试代码
People p1(18);
    cout << "p1's age " << p1.getAge() << endl;
    People p2 = p1;
    cout << "p2's age " << p2.getAge() << endl;
    p2 = p1;

 

 

通过上面的输出结果我们发现:

= 什么时候会调用Copy Constructor呢?在初始化的时候,也就是第一个 People p2 = p1。因为Copy Constructor 是一种 Constructor,也是负责初始化的。

什么时候=是赋值呢?两个都已经初始化,再调用=就是赋值了。

 

4. 浅拷贝和深拷贝

 

我们上面的类People只有一个简单的属性age,还是int类型的,进行简单的赋值就是浅拷贝,但是People类将来会变的复杂起来,后面可能会增加指针类型的属性。那么就会涉及到深拷贝了。

 

我的理解就是:浅拷贝:两个变量进行浅拷贝时,它们指向同一个地址,它们的值相同。这样会有问题,当其中的一个析构了那个地址,另外一个也没有了,有时候会发生错误,但浅拷贝比较廉价。

深拷贝:两个变量进行深拷贝时,第二变量会重新申请一块区域来存放跟第一个变量指向地址的值。两个东西完全是独立的,只是值相同。消耗比较大,因为要重新申请空间。

关于Copy Constructor,就先这样吧。

 

 

5.禁用Copy Constructor

 

把Copy Constructor设置为private就行了。以我的水平,我还不知道什么情况要这样做 =。=

 

http://www.waitingfy.com/archives/1033

Tags: ,

1033

Leave a Reply

Name and Email Address are required fields.
Your email will not be published or shared with third parties.