C++:构造函数、拷贝构造函数与运算符重载

释义:

  • 构造函数:初始化对象的数据成员的一种函数。
  • 拷贝构造函数:以本类的对象引用作为参数的构造函数,目的是拷贝对象。
  • 运算符重载:重新定义运算符行为,用以适应不同的数据类型,本质为函数重载。

示例:

下面这个简单的例子分别描述了带参构造函数、拷贝构造函数和赋值运算符重载。

class A{
    public:
    int a;
    //constructor
    A(int a_tmp){
        a = a_tmp;
    }
    //copy constructor
    A(const A& A_tmp){
        a = A_tmp.a;
    }
    //member assignment operator
    A& operator=(const A& A_tmp){
        a = A_tmp.a;
        return *this;
    }
}
//non-member operator overload
A operator+(const A& A1,const A& A2){
    A A_tmp;
    A_tmp.a = A1.a+A2.a;
    return A_tmp;
}

思考:

  1. 拷贝构造函数的理解:
    • 拷贝构造函数的重点是构造函数,因此copy ctor只有在变量的定义处才会被调用,本质还是一种构造函数。
    • 如果没有显式定义拷贝构造函数,那么编译器会为类自动定义一个按位拷贝的默认拷贝构造函数。需要注意默认拷贝构造函数只会对成员变量做简单的赋值运算来完成拷贝动作,因此对于指针型变量会出现浅拷贝的问题。(浅拷贝:src和dst是同一块内存区域;深拷贝:src和dst不在同一块内存区域。)
    • 禁止拷贝构造函数:将拷贝构造函数声明为private可以禁止使用拷贝构造函数。一般而言,将构造函数声明为private都可以禁止调用。这就是单例模式的实现方式。
    • 对于B:A这种派生类,B的默认构造函数会调用A的默认构造函数,如果重载了B的构造函数,若需要指定A的构造函数,则需要显式调用,否则会调用A的默认构造函数。例如如果要调用A的拷贝构造函数,则需要这样写:
B(const B& B_tmp):A(B_tmp){
    ...
}
  1. 运算符重载的理解:
    • 为什么运算符重载的返回值大多都是引用之一:原理上来说返回值可以为任何类型,比如可以为基本类型、类或者void,但是基于两个方面考虑,一方面是为了便于连续运算,比如a=b=c,b=c运算完为了能继续给a赋值,=运算符会返回左值b,这里的左值可以是对象也可以是对象的引用。但是,另一方面,如果返回了对象,那么在函数返回后会调用构造函数创建临时变量用于存储返回值进行下一次a=运算,相比返回对象引用开销更大,因此返回对象的引用是性能较好而且更通用的做法。
    • 为什么运算符重载的返回值大多都是引用之二:实际上返回引用意味着有能力返回左值,C++ 中函数可以返回左值的功能对实现一些重载的操作符是非常重要的,比如方括号运算符[],返回引用意味着能进行类似myVector[2] = 3.5这样的操作。
    • 注意成员运算符重载和非成员运算符重载的差异,他们的参数个数是不一样的,见上述代码。
    • 对于B:A这种派生类,运算符重载需要显式调用A的对应运算符,否则A类内部不会发生任何改变。例如:
B& operator+(const B& B_tmp){
    A:operator+(B_tmp);
    ...
    return *this;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容