转自:http://tieba.baidu.com/f?kz=727217617
(1)为什么要使用拷贝构造函数?
(2)拷贝构造函数的概念 (3)什么时候用到拷贝构造函数? 默认拷贝构造函数的行为如下: 拷贝构造函数是用一个存在的对象去构造另一个不存在的对象
转自:http://www.vckbase.com/document/viewdoc/?id=788
重点:包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符。
以下讨论中将用到的例子:
class
CExample
{ public : CExample(){pBuffer = NULL; nSize = 0 ;} ~ CExample() {delete pBuffer;} void Init( int n) { pBuffer = new char [n]; nSize = n;} private : char * pBuffer; // 类的对象中包含指针,指向动态分配的内存资源 int nSize; };
这个类的主要特点是包含指向其他资源的指针。 pBuffer指向堆中分配的一段内存空间。
一、拷贝构造函数
语句"CExample theObjtwo=theObjone;"用theObjone初始化theObjtwo。 其完成方式是内存拷贝,复制所有成员的值。 完成后,theObjtwo.pBuffer==theObjone.pBuffer。 即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。 所以需要采用必要的手段来避免此类情况。 回顾以下此语句的具体过程:首先建立对象theObjtwo,并调用其构造函数,然后成员被拷贝。 可以在构造函数中添加操作来解决指针成员的问题。 所以C++语法中除了提供缺省形式的构造函数外,还规范了另一种特殊的构造函数:拷贝构造函数,上面的语句中,如果类中定义了拷贝构造函数,这对象建立时,调用的将是拷贝构造函数,在拷贝构造函数中,可以根据传入的变量,复制指针所指向的资源。
拷贝构造函数的格式为:构造函数名(对象的引用) 提供了拷贝构造函数后的CExample类定义为:
这样,定义新对象,并用已有对象初始化新对象时,CExample(const CExample& RightSides)将被调用,而已有对象用别名RightSides传给构造函数,以用来作复制。
原则上,应该为所有包含动态分配成员的类都提供拷贝构造函数。
拷贝构造函数的另一种调用。
当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调同拷贝构造函数。 例如
还有一种情况,也是与临时对象有关的 当函数中的局部对象被被返回给函数调者时,也将建立此局部对象的一个临时拷贝,拷贝构造函数也将被调用
二、赋值符的重载 下面的代码与上例相似
int
main(
int
argc,
char
*
argv[])
{ CExample theObjone; theObjone.Init( 40 ); CExample theObjthree; theObjthree.Init( 60 ); // 现在需要一个对象赋值操作,被赋值对象的原内容被清除,并用右边对象的内容填充。 theObjthree = theObjone; return 0 ; } 也用到了"="号,但与"一、"中的例子并不同,"一、"的例子中,"="在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号表示。 例如 CExample theObjone(theObjtwo); 而本例子中,"="表示赋值操作。将对象theObjone的内容复制到对象theObjthree;,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。 但"="的缺省操作只是将成员变量的值相应复制。旧的值被自然丢弃。 由于对象内包含指针,将造成不良后果:指针的值被丢弃了,但指针指向的内容并未释放。指针的值被复制了,但指针所指内容并未复制。
因此,包含动态分配成员的类除提供拷贝构造函数外,还应该考虑重载"="赋值操作符号。 类定义变为:
class
CExample
{ ... CExample( const CExample & ); // 拷贝构造函数 CExample & operator = ( const CExample & ); // 赋值符重载 ... };
//
赋值操作符重载
CExample & CExample:: operator = ( const CExample & RightSides) { nSize = RightSides.nSize; // 复制常规成员 char * temp = new char [nSize]; // 复制指针指向的内容 memcpy(temp,RightSides.pBuffer,nSize * sizeof ( char )); delete []pBuffer; //删除原指针指向内容 (将删除操作放在后面,避免X=X特殊情况下,内容的丢失) pBuffer=temp; //建立新指向 return*this; } 三、拷贝构造函数使用赋值运算符重载的代码。
|
相关文章
- C++ 默认拷贝构造函数 深度拷贝和浅拷贝
- C#委托(delegate)的常用方式- 委托的定义 // 委托的核心是跟委托的函数结构一样 public delegate string SayHello(string c); public delegate string SayHello(string c);:定义了一个公共委托类型 SayHello,该委托接受一个 string 类型的参数 c,并返回一个 string 类型的值。 Main 方法 static void Main(string args) { // 本质上其实就是把方法当作委托的参数 SayHello sayC = new SayHello(SayChinese); Console.WriteLine(sayC("欢迎大家")); SayHello sayE = new SayHello(SayEgnlish); Console.WriteLine(sayE("Welcome to")); // 简单的写法:必须类型一样 SayHello s1 = SayChinese; SayHello s2 = SayEgnlish; Console.WriteLine(s1("好好好")); Console.WriteLine(s2("Gooood")); // 最推荐 SayHello ss1 = con => con; Console.WriteLine(ss1("niiiice")); // 匿名委托:一次性委托 SayHello ss3 = delegate(string s) { return s; }; Console.WriteLine(ss3("说中国话")); } 常规实例化委托 SayHello sayC = new SayHello(SayChinese);:创建了一个 SayHello 委托的实例 sayC,并将 SayChinese 方法作为参数传递给委托的构造函数。 Console.WriteLine(sayC("欢迎大家"));:通过委托实例调用 SayChinese 方法,并输出结果。 同理,SayHello sayE = new SayHello(SayEgnlish); 和 Console.WriteLine(sayE("Welcome to")); 是对 SayEgnlish 方法的委托调用。 简化的委托赋值方式 SayHello s1 = SayChinese; 和 SayHello s2 = SayEgnlish;:当委托类型和方法签名一致时,可以直接将方法赋值给委托变量,无需使用 new 关键字。 Console.WriteLine(s1("好好好")); 和 Console.WriteLine(s2("Gooood"));:通过委托实例调用相应的方法。 使用 Lambda 表达式实例化委托 SayHello ss1 = con => con;:使用 Lambda 表达式创建委托实例 ss1,con => con 表示接受一个参数 con 并返回该参数本身。 Console.WriteLine(ss1("niiiice"));:通过委托实例调用 Lambda 表达式。 匿名委托 SayHello ss3 = delegate(string s) { return s; };:使用匿名委托创建委托实例 ss3,delegate(string s) { return s; } 是一个匿名方法,直接在委托实例化时定义了方法体。 Console.WriteLine(ss3("说中国话"));:通过委托实例调用匿名方法。 委托引用的方法定义 public static string SayChinese(string content) { return content; } public static string SayEgnlish(string content) { return content; } public static string SayChinese(string content) 和 public static string SayEgnlish(string content):定义了两个静态方法,分别接受一个 string 类型的参数 content,并返回该参数本身。这两个方法的签名与 SayHello 委托一致,可以被 SayHello 委托引用。 常规的委托实例化、简化的赋值方式、Lambda 表达式和匿名委托。委托在 C# 中是一种强大的机制,它允许将方法作为参数传递,实现了代码的灵活性和可扩展性。
- C++ Primer 学习笔记_54_类和数据抽象 --拷贝构造函数、赋值运算符
- 移动构造函数和拷贝构造函数的使用
- 《Effective C++》《构造/析构/赋值运算——9、绝不在构造和析构过程中调用virtual函数》
- 关于构造函数和原型prototype对象的理解
- 【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符
- C++类和对象-C++运算符重载->加号运算符重载、左移运算符重载、递增运算符重载、赋值运算符重载、关系运算符重载、函数调用运算符重载
- 剑指offer:赋值运算符函数和复制构造函数
- C++本质:类的赋值运算符=的重载,以及深拷贝和浅拷贝