由于没有接触过C#,不知《大话设计模式》所云。但无看了《大话设计模式》觉得非就是深拷贝和浅拷贝的问题。在此谈谈我对C++深拷贝与浅拷贝的认识,不足之处请指出。
对编程来说简单的复制粘贴极有可能造成重复代码的灾难,也很容易造成存在问题的代码的传播。
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型对象创建新的对象。
通俗的说就是从一个对象再创建另一个可定制的对象,而且不知道任何创建的细节。
拷贝分为浅拷贝和深拷贝。浅拷贝是C++默认的拷贝方式。通过逐个成员赋值的方式来实现的。比如对类
class Time
{
public:
int month;
int day;
int year;
};
如有Time a;
Time b=a;
//或是Time b(a);
此时将会调用复制构造函数,采用将a的成员变量逐个赋值给b对应的成员变量的浅拷贝方式。类似的情况还有Timeb;b=a;与上面代码的区别在于b多调用一次默认构造函数,在b=a是调用的是默认的重载赋值运算符函数。Timeb=a;仍是调用的复制构造函数,而不是调用重载的赋值运算符函数,这一点要清楚。
复制构造函数和默认的赋值运算符采取的就是浅拷贝的方式。调用复制构造函数有以下几种情况:一:按值传递对象时。二:函数返回对象时。三:用一个对象初始化另一个对象时Timea(b),或是Timea=b。C++默认的赋值和复制构造函数中都是浅拷贝,如果需要深拷贝的话需要自己实现。
对于一般的成员变量浅拷贝与深拷贝没有本质的区别,而对于类中包含动态分配内存的指针类型的成员变量时,逐个成员赋值可能会引发严重的问题。此时两个对象的指针成员变量指向相同的堆空间,一旦有一个对象将此空间释放,另一个再次访问将会发生访问违规的情况,导致程序非正常终止。可以通过重写赋值运算符函数和复制构造函数来实现深拷贝。
实现深拷贝时,如b=a,会在堆中开辟另一块空间,它与a的成员变量ptr指向的堆空间存储的内容完全相同。开辟的新的堆空间的首地址赋值给b的ptr。就实现了每个对象的的ptr指向不同的堆空间,其中一个对象的堆空间释放与否不会对另一个对象造成影响。
#include<iostream>
using namespace std;
class A
{
public:
int a;
int *b;
public:
A()
{
a=0;
b=new int;
*b=0;
}
A(int aa,int bb)
{
a=aa;
b=new int;
*b=bb;
}
A(A& aa)
{
b=new int;
a=aa.a;
*b=*aa.b;
}
};
int main(int argc,char**argv)
{
A AA(20,40);
A BB(AA);
A CC;//A CC=AA;等同于A CC(AA);
CC=AA;
cout<<AA.a<<", "<<*AA.b<<endl;
cout<<BB.a<<", "<<*BB.b<<endl;
cout<<CC.a<<", "<<*CC.b<<endl;
*AA.b=80;
cout<<AA.a<<", "<<*AA.b<<endl;
cout<<BB.a<<", "<<*BB.b<<endl;
cout<<CC.a<<", "<<*CC.b<<endl;
return 0;
}