C++中拷贝构造函数、浅拷贝与深拷贝的详解

来源:互联网 发布:天刀怎样下载捏脸数据 编辑:程序博客网 时间:2024/06/03 21:29

拷贝构造函数调用时机:

1、对象需要通过另外一个对象进行初始

化:

     T t1(10, 20);T t2(0, 0);T t3 = t1; // 拷贝构造函数调用的时机一:T t4(t2);  // 拷贝构造函数调用的时机 二:

2、实参传递给形参时调用赋值构造函数 拷贝构造函数调用的时机三:

class T{public:T(int m, int n){cout << "gouzao" << endl;a = m;b = n;c = 'q';}T(const T& obj){cout << "fuzhi" << endl;a = obj.a + 10;b = obj.b - 5;c = obj.c;}~T(){cout << "xigou" << endl;}int a;int  b;char c;int get_A(){return  a;} int get_B(){return  b;}};void f(T t){t.a = 100;t.b = 102;}
void main()

{f(t1)};

3 返回匿名对象时,对象以值传递的方式从函数返回

T  go()//
{
T A(100,102);

return A;  //返回匿名对象
}

//匿名对象的去和留
//如果用匿名对象初始化一个同类型的对象,匿名对象转化为有名对象 T m1=go();该对象的生命周期结束时才析构
//如果用匿名对象赋值 给另一个同类型的对象,匿名对象立即被析构  T m2(10,9);m2=go()

二:

浅拷贝与深拷贝 解析:

#define  _CRT_SECURE_NO_WARNINGS

#include<iostream>

#include<string>

using namespace std;

class Name

{

public:

Name(const char*myp)

{

len = strlen(myp);

p = (char*)malloc(len+1);

strcpy(p,myp);

}

~Name()

{

if (p != NULL)

free(p);

p = NULL;

len = 0;

}

private:

char* p;

int len;

};

void mainplay()

{

Name obj1("abcdef");

Name obj2 = obj1;//问题:在执行这句话时,当函数体结束时,要析构对象(且析构两次),同一个内存地址被同时free两次,所以会出错

//用obj1来初始化obj2,要执行拷贝构造函数

//由于自己没有定义拷贝构造函数,所以编译器会自动调用默认的拷贝构造函数,编译器提供的默认的拷贝构造函数是浅拷贝

//浅拷贝是指:只赋值了指针的值,而指针所指向的内存空间的内容没有被赋值,浅拷贝的结果是obj1和obj2同时指向了同一个内存空间

编译器提供的默认的拷贝构造函数,就是把指针的值(即obj的属性值 char* p,int len)赋值给obj2,而并没有开辟一个新的内存空间,把内存空间的内容(abcdefg)赋值给obj2.所以导致同一个内存空间被同时析构两次时出错,

解决方案:  深拷贝构造函数自己写拷贝构造函数,在开辟一个新的内存空间,然后把空间中内容拷贝到新的内存空间

Name(const Name&obj)

{

len = strlen(obj.p);

p = (char*)malloc(len + 1);

strcpy(p,obj.p);

 

}

Name obj3("obj3");

obj3 = obj1;

}

Obj1和obj3指向了统一内存空间,使程序崩溃。

解决等号运算符与浅拷贝带来的问题方法就是:重载等号运算符,在函数中重新开辟一段内存空间为obj3对象所用,但是由于之前obj3已经开辟了内存空间,为了防止内存泄漏,,需要先对内存空间进行释放,然后再重新建新的内存空间。 

Name& operator=(Name&obj)

{

if (p != NULL)

{

delete[] p;

p = NULL;

len = 0;

}

p = (char*)malloc(strlen(obj.p)+1);

if (p != NULL)

strcpy(p,obj.p);

len = obj.len;

return *this;

}

void main()

{mainplay();

cout << "successful" << endl;

}

 拷贝构造函数的几个细节

1. 拷贝构造函数里能调用private成员变量吗?
解答:
这个问题是在网上见的,当时一下子有点晕。其时从名子我们就知道拷贝构造函数其时就是
一个特殊的构造函数,操作的还是自己类的成员变量,所以不受private的限制。


2. 以下函数哪个是拷贝构造函数,为什么?

[c-sharp] view plain copy
  1. X::X(const X&);      
  2. X::X(X);      
  3. X::X(X&, int a=1);      
  4. X::X(X&, int a=1, int b=2);  


解答:对于一个类X, 如果一个构造函数的第一个参数是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.

[c-sharp] view plain copy
  1. X::X(const X&);  //是拷贝构造函数      
  2. X::X(X&, int=1); //是拷贝构造函数     
  3. X::X(X&, int a=1, int b=2); //当然也是拷贝构造函数  


3. 一个类中可以存在多于一个的拷贝构造函数吗?
解答:
类中可以存在超过一个拷贝构造函数。

[c-sharp] view plain copy
  1. class X {   
  2. public:         
  3.   X(const X&);      // const 的拷贝构造  
  4.   X(X&);            // 非const的拷贝构造  
  5. };  


注意,如果一个类中只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化.

[c-sharp] view plain copy
  1. class X {      
  2. public:  
  3.   X();      
  4.   X(X&);  
  5. };      
  6.   
  7. const X cx;      
  8. X x = cx;    // error  


如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。
这个默认的参数可能为 X::X(const X&)或 X::X(X&),由编译器根据上下文决定选择哪一个。



阅读全文
0 0