拷贝构造函数定义时未加const修饰形参

前言

最近复习c++中,类相关的知识。在做默认构造和拷贝构造相关实验的过程中,遇到了一个很疑惑的问题。后来才发现,是由于编写的时候语法不规范导致的(不应该被修改的实参,引用形式传入时加const限定)。所以在这里记录一下,如果有其他小伙伴遇到了,也能作一个提醒。

问题描述以及解决方案

在visual studio中,定义了如下的拷贝构造函数以及重载运算符= 

class Complex{       //复数类的定义
public:
    Complex(Complex& c)   //拷贝构造    
    {
    	cout << "拷贝构造" << endl;
	    this->real = c.real;
	    this->image = c.image;
    }

    Complex& operator=(Complex& c)   //重载=
    {
    	cout << "重载=的调用" << endl;
    	this->real = c.real;
    	this->image = c.image;
    	return *this;
    }


private:
    double real;
    double image;
};

上面的代码,咋一看好像没什么问题,而且在visual c++ 6.0中,这样定义出来的拷贝构造函数和重载出来的=操作符是可以正常使用的。但是如果放在visual studio中,就会出现很诡异的错误。

首先是拷贝构造的问题:

Complex c4采用的是拷贝构造来进行初始化,但是会发现编译器提示你没有适当的拷贝构造函数可以使用,但是明明前面已经定义了。

这样的问题也会出现在重载运算符=上:

 它提示你没有Complex = Complex的“=”运算符可以使用。我当时看到的时候,就真的:)

 而解决的办法在就像在前言中讲到的那样,给这两个函数定义的形参前加上const修饰后,上面的两个错误都会消失

所以你会发现,解决方法就只是用了一句话来说明,但是前面却说了一大堆,我也纠结了快一下午,只能说确实心累。  (其实搜 "重载=的注意事项" ,大部分文章都会告诉你要加const (捂脸) )

默认构造函数中默认参数的使用

这里再补充一点关于默认参数的使用。基于上面的复数类Complex,当要求你实现:复数与复数之间、复数与整数之间、复数与浮点数之间的加法运算时,你会如何去定义重载+函数?

正常的思路就是:由于重载运算符+时,形参列表只能是一种数据类型。为此,就需要定义三个运算符+的重载函数。

Complex operator+(int c);       //复数与整型
Complex operator+(double c);    //复数与双精度浮点数
Complex operator+(const Complex& c);  //复数与复数

但是当我们利用好默认构造函数以及隐式类型转换时,可以只通过定义一个复数与复数之间的重载运算符+函数,就完成上面的三个要求。

为此,我们首先需要在复数类的默认构造函数用上默认参数。目的是:当不指定实部和虚部大小时,默认定义出来的复数的实部与虚部都为0。同时,当你只指定一个参数时,(该参数无论是int还是double,最终都会被转换成double类型) 构造出来的是只有实部的复数。

Complex(double rel = 0,double img = 0):real(rel),image(img){}  //默认构造函数


Complex c2;     // c2 = 0 + 0j
Complex c3(1);  // c3 = 1 + 0j

于是,我们就可以只用operator+(const Complex& c),来完成上面的三个要求:

Complex c2(3);
Complex c3,c4;  

c3 = c2 + 1;     //复数与整数
c4 = c3 + 1.5;   //复数与浮点数
c2 = c3 + c4;    //复数与复数    

要理解为什么能这么做,主要就是要理解整数与浮点数作为实参传递给复数类引用的过程。对此,你可以配合着拷贝构造的调用时机来理解。

当实参以值传递的方式给函数参数传值时,它其实会先调用一次拷贝构造函数,然后把拷贝出来的类对象传入函数。当运行c3 = c2 + 1时,也是同理。它本质上是调用operator+函数,实参为整型1,但形参为引用形式的复数类。这种情况下,会调用Complex类中的默认构造函数,利用传入的整型1构造出来一个复数类,然后将这个复数类对象( 1+0j )传入函数中完成运算

其实在这里,当你重载操作符+时,定义出来的是operator+(Complex& c)的形式,即没有加const.你就会发现,它也无法编译通过,无法完成默认构造函数的调用。

结语

这个故事告诉我们,当使用引用作参数传递时,就一定要多考虑一下,如果它原本的值不应该被改变,就要养成加上const修饰的习惯。关于隐式类型转换,感兴趣的可以参考我的上一篇文章。欢迎带伙交流~

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值