`

C++书写拷贝构造函数,重载赋值操作符和clone函数需要注意问题

阅读更多

对于C++类:显示地写出拷贝构造函数,重载赋值操作符和析构函数是良好的习惯,但在写构造函数时需要注意一些容易出现的错误,如下面的代码:

 

#include <iostream>
using namespace std;
 
class M{
public:
    M(){}
    M(const M &m){
       cout<<"copy construtor"<<endl;
       operator =(m);
    }
    M operator =(const M &m){   //问题出在此处
       cout<<"operator ="<<endl;
       return *this;
    }
};
 
int main() {
    M m1;
    M m2;
    m2=m1;
    return 0;
}


在下面三种情况下会调用拷贝构造函数:

(1)用一个已经实例化了的该类对象,去实例化该类的另外一个对象;

(2)用该类的对象传值的方式作为一个函数的参数;

(3)一个函数返回值为该类的一个对象。

特别地,对于语句 M m;  M mm=m; 属于(1)情况,即语句M mm=m;调用的是拷贝构造函数,而不是构造函数。

 

但在重载=操作符时,返回值不是引用类型将导致程序运行出现严重问题。即如果出现上面会调用拷贝构造函数的三种情况之一,或者使用=操作符时,拷贝构造函数和operator =将循环递归调用,导致程序出现死循环。原因是拷贝构造函数和operator =之间不断地重复调用。

解决办法:将operator =的返回类型改为引用类型M&,此时调用operator =时不会去调用拷贝构造函数。

 

还有,若要写clone时,若通过下面的方式:

    M clone(){

       cout<<"clone"<<endl;

       return *this;

    }

前提是拷贝构造函数不能调用clone来完成拷贝,否则出现上面同样的问题,下面的代码就会出现这样的问题

    M(const M &m){

       cout<<"copy construtor"<<endl;

       clone();

    }

总之,在写这些函数时,要特别留意彼此的调用关系。

以下是我的惯用写法:

(A)对于拷贝构造函数和重载=操作符

    M(const M &m){

       cout<<"copy construtor"<<endl;

       operator =(m);

    }

    M& operator =(const M &m){  //问题出在此处

       cout<<"operator ="<<endl;

       /* 此处写上成员数据的拷贝 */

       return *this;

    }

这里写成了inline函数,只是方便说明问题,其实不必非要这么写,可以采取先声明,后定义的常规方法。

(B)对于clone函数

声明:  virtual M clone();   //考虑继承时的多态

定义:  M M::clone(){

       cout<<"clone"<<endl;

       //将在调用处直接调用构造函数,效率高,避免返回局部变量,更安全

       return M();

    }

 

 

 

 

3
0
分享到:
评论

相关推荐

    2.1.4 C++和C#数据传递 -class类型传递

    C++提供了更多的控制,允许按值和按引用传递,并需要开发者处理拷贝构造函数和赋值操作符。而C#则通过隐式的引用传递简化了这一过程,但在处理复杂对象时,仍需考虑如何正确地复制和赋值。理解这些差异对于编写高效...

    java面试宝典

    - 理解`==`操作符用于比较原始类型和引用类型的基本区别。 - `equals()`方法用于比较对象的内容是否相等,适用于引用类型。 12. **字符串的不可变性** - 字符串在Java中是不可变的,了解这一点对内存管理和性能...

    Java面试宝典

    - `&&`:逻辑与操作符,具有短路效果,即左侧表达式为`false`时右侧表达式将不再计算。 **2. 用最有效率的方法算出2乘以8等于几?** - 使用位运算`来表示乘以2的幂次方,如`2 等于2乘以2的3次方。 **3. 存在使i+1...

    java面试宝典2010版

    `short`类型赋值操作 - **知识点**: 使用`short`类型的变量进行加法操作时需要注意自动类型提升。 - **解释**: 当`short`类型变量与另一个数值类型相加时,结果会被自动提升为`int`类型。如果想将结果赋值给`short`...

    计算机英语(编程词汇大全).pdf

    "Arrow operator"通常指的是C++中的箭头操作符,用于访问对象的成员。 "Array"是编程中的常见数据结构,用于存储一系列相同类型的数据。"Assembly"既指硬件层面的装配件,也指软件层面的汇编语言。"Assert"是编程中...

    2011年最全Java面试题

    在逻辑运算中,`|`表示按位或操作符,而`||`表示逻辑或操作符,且具有短路特性。当左侧表达式为真时,`||`右侧表达式将不会被评估,这可以避免不必要的计算,提高效率。 ### 4. Java类型系统 Java是一种强类型语言...

    程序员英语词汇.docx

    - **定义**: 用于调用函数的操作符。 - **应用场景**: 函数调用的基本语法。 #### 25. 候选函数 (Candidate Function) - **定义**: 当解析函数调用时,根据名字查找得到的所有匹配函数。 - **应用场景**: 函数重载...

    CoreJava学习笔记

    Java支持多种操作符,包括算术操作符、赋值操作符、比较操作符、逻辑操作符等。 **数字类型之间的转换:** Java中不同数字类型之间的转换可以通过自动类型提升或显式的强制类型转换来实现。 **强制类型转换:** ...

    计算机编程常用英语单词.doc

    11. **Assignment Operator** - 赋值操作符:如 `=`,用于将右侧的值赋给左侧的变量。 12. **Associated** - 相关的:指两个或多个元素之间存在某种关系或连接。 13. **Associative Container** - 关联式容器:数据...

    java牛人总结

    `这段代码将引发编译错误,因为`1`和`+`操作符的默认类型是`int`,因此`+`操作会将`short`类型的`s1`提升为`int`类型,再将结果赋值给`short`类型的`s1`时,会导致类型不匹配。而`short s1 = 1; s1 += 1;`则不会引发...

    2012-Java面试宝典new版

    **答案**: 写`clone()`方法时,通常会有`super.clone()`这行代码,用于调用父类的`clone()`方法实现浅拷贝。 #### 22. 面向对象的特征 **问题**: 面向对象的特征有哪些方面 **答案**: 面向对象编程(OOP)的主要...

    计算机编程常用英语单词..docx

    51. **call operator**:调用操作符,用于调用函数或方法。 52. **candidate function**:候选函式,在多态或多载函数选择中可能出现的函数。 53. **chain**:串链,一系列连续的操作或事件。 54. **character**...

    Java技术要点与面试经典2013版

    通常需要注意类型转换、空指针异常、数组越界等问题。 17. `public`表示所有地方都可以访问,`private`只允许在本类中访问,`protected`允许在本类、同一包的类和子类中访问,无修饰符(默认)则仅限于同一包内的...

    计算机编程常用英语单词.pdf

    42. **call operator**:调用操作符,用于调用对象的方法或函数。 43. **candidate function**:候选函式,在函数多载中可能匹配的函数之一。 44. **chain**:串链,一系列连续的调用或操作。 45. **character**...

    编程常用英语单词.pdf

    55. **Class Definition**:类别定义,包含类的所有详细信息,如成员函数和数据成员。 56. **Class Derivation List**:类别衍化列,用于继承声明中列出的基类。 57. **Class Hierarchy**:类别继承体系,描述类...

    java 面试宝典 免费提供

    - C++的虚类可以有虚函数和数据成员。 - Java接口更倾向于功能的组合,而C++虚类强调的是继承层次结构。 #### 三十六、`.java`文件与类 - 一个`.java`文件可以包含多个类,但只能有一个公共类,并且文件名需要与该...

Global site tag (gtag.js) - Google Analytics