C++类与对象——拷贝构造函数

C++拷贝构造函数

问题引入

#include<iostream>

using namespace std;

class A{
public:
    A(int a,int b):a(a),b(b){}

    void printA(){
        cout<<"class A.value a is:"<<a<<endl;
    }

    void printB(){
        cout<<"class A.value b is:"<<b<<endl;
    }
private:
    int a;
    int b;
};

int main(int argc, char *argv[]){

    A a(10,20);
    A b = a; // 声明一个A的变量b,并通过赋值操作给b进行赋值
    a.printA();
    a.printB();
    b.printA();
    b.printB();

    return 0;
}
class A.value a is:10
class A.value b is:20
class A.value a is:10
class A.value b is:20

上面的代码中,可以看到在main函数里面存在,A b = a的拷贝构造操作需要区分拷贝构造和赋值的区别,后面有提到,往后看,但是因为没有重载赋值运算符和拷贝构造函数,C++会自作主张的对类A生成一个默认拷贝操作

其等价于

A b = a;
// 或者写成
A b(a);

// 等价于
b.a = a.a;
b.b = a.b;

这是C++自动生成的赋值方式和拷贝构造方式,但是,如果类A里面加一个指针变量,并在析构函数里面删除这个指针时,再看操作,代码如下

#include<iostream>

using namespace std;

class A{
public:
    A(int a,int b,int c):a(a),b(b){
        this->c = new int(c);
    }

    ~A(){
        cout<<"~A()"<<endl;
        delete c;
        c= nullptr;
    }

    void printA(){
        cout<<"class A.value a is:"<<a<<endl;
    }

    void printB(){
        cout<<"class A.value b is:"<<b<<endl;
    }
private:
    int a;
    int b;
    int *c;
};

int main(int argc, char *argv[]){

    A a(10,20,20);
    A b = a; // 声明一个A的变量b,并通过赋值操作给b进行赋值
    a.printA();
    a.printB();
    b.printA();
    b.printB();
    cout<<"i will end"<<endl;

    return 0;
}

再次运行程序,得到结果

class A.value a is:10
class A.value b is:20
class A.value a is:10
class A.value b is:20
i will end
~A()
~A()

进程已结束,退出代码-1073740940 (0xC0000374)

再次运行,发现程序已经不能正常退出,而是出现了错误,如果正常运行的情况下,C++在退出时会调用A的析构函数,理论上是输出两次~A,但是为什么会出现了错误?从C++自定以的拷贝与赋值操作分析,A b = a等价于

b.a = a.a;
b.b = a.b;
b.c = a.c;

在这里可以看到,b和c的指针变量都指向了同一个位置,这也就导致了在执行析构的时候指针被delete了两次,这也就直接导致了错误的原因,并且不只这一个问题,还有

  • 因为b和c的指针都指向了同一个内存位置,修改b的指针属性,c也会受影响,如果我们希望这样的话就当我没说

所以,在这种情况下,在某些类的定义中,因为C++自定义的这类拷贝和赋值操作不满足我们的要求,比如有指针变量的情况,需要我们自定义拷贝构造函数

拷贝构造函数定义的格式为:

classname(const classname &var){
    .....
}

如果对上面的代码加一个拷贝构造函数或者重载以下运算符的化

A(const A &src):a(src.a),b(src.b){
    int tmp = *src.c;
    c = &tmp;
}

运行结果为

class A.value a is:10
class A.value b is:20
class A.value a is:10
class A.value b is:20
i will end
~A()
~A()

进程已结束,退出代码0

重写拷贝构造函数是为某些通过C++默认拷贝构造函数的逻辑构造的类而去定义的,对于类的拷贝,建议写成如下形式

A b(a);

而不要写成,因为容易把他理解成==A b; b=a;==的赋值操作,但是两者是有区别的

A b = a; // 这是调用类A的拷贝构造
b = a; 	 // 这是赋值操作
  • 拷贝操作时调时自定义的拷贝构造函数或默认的拷贝构造函数
  • 而赋值操作时调用赋值运算符,如果重载了的化就是重载后的,没有的话就是默认的

可以用一段代码来验证以下两者的区别

#include<iostream>

using namespace std;

class A{
public:
    A(int a,int b):a(a),b(b){}

    A(const A &src):a(src.a),b(src.b){
        cout<<"Use Copy Constructor"<<endl;
    }

    A& operator=(const A &src){
        cout<<"Use Operator Assign"<<endl;
        if(this != &src){
            a = src.a;
            b = src.b;
        }
        return *this;
    }
private:
    int a;
    int b;
};

int main(int argc, char *argv[]){
    A a(10,20);
    A b(9, 9);
    A c = a;  // 这是拷贝构造
    b = a;	  // 这是赋值操作
    return 0;
}
Use Copy Constructor
Use Operator Assign

进程已结束,退出代码0

注意区分!并且重载赋值运算符也是同样的原理,其重载格式为

A& operator=(const A&src){
    ....
}

// 右值引用形式
A& operator=(A &&src){
   ....
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值