重载运算符时是作为成员函数还是非成员函数?
对于很多运算符来说,可以选择使用成员函数或者非成员函数来实现运算符重载,一般来说,非成员函数应该是友元函数,这样才能够使非成员函数可以访问类的私有数据。
非成员版本的重载运算符所需要的形参数目与运算符使用的操作数数目相同,而成员版本所需要的参数数目少一个,因为其中一个操作数是被隐式传递的。
假如要重载加法运算符,可以有下面两种形式:
stock operator+(const stock& s1)const;
friend stock operator+(const stock& s1,const stock& s2);
但是在定义时必须选择其中的一种形式,否则会引发冲突,导致编译错误。
正如前面所说的,一些运算符只有成员函数是唯一合法的选择
请看这里的重载限制
但是有一些则使用非成员函数更好,比如说重载<< 运算符。
对于定义重载运算符函数时的一些小方法
- 如果方法通过计算得到一个新的类对象,可以考虑是否能够使用类构造函数来完成这个任务,这样做可以避免麻烦并且确保对象按照正确的方式创建。
比如说使用成员函数重载加法运算符:
stock stock::operator+(const stock& s)const
{
return stock(value1+s.value1,value2+s.value2);
}
比如说重载乘法运算符时:
stock operator*(const double a)const
{
return stock(value1*a,value2*a);
}
friend stock operator*(double a,const stock& s)
{
return s*a;
}
- 运算符重载通过函数实现,所以只要运算符函数的特征标不同,使用运算符数量与相应的内置C++运算符相同,就可以多次重载同一个目标。
比如说重载 - 运算符
stock operator-(const stock&a)const
{
return stock(value1-a.value1,value2-a.value2);
}
stock operator-()const
{
return stock(-value1,-value2);
}
类型转换
接受一个参数的构造函数为将类型与该参数相同的值转换为类提供了蓝图,我们可以使用下面的构造函数将double类型值转换为类对象:
stock(double a);
也就是可以这样编写:
stock s1=1.414;
程序使用构造函数创建一个临时对象,然后通过逐成员赋值的方法将临时对象的值给所创建的对象,然后删除临时对象。
只有接受一个参数的构造函数才能够作为转换函数,但是如果第一个参数后的其他参数有默认参数,那么就可以定义具有多个参数的构造函数实现转换函数:
stock(double a,int b=0);
stock s2=2.732;
将构造函数用于自动类型转换似乎是一种不错的特性,但是这却可能导致意想不到的类型转换,C++新增了关键字explicit (显式的)可以用于关闭这种功能,只要在声明构造函数时在前面加上这个关键字声明即可。
explicit stock(double a);
这将关闭隐式转换,但是仍然允许使用显示转换,可以显示强制转换:
double a=456.123;
stock s1=(stock)a;
stock s2=stock(a);
编译器在什么时候才能够使用类型转换函数呢?在使用上面的关键字后,只能够显示强制转换,没有用的情况下(以上面的构造函数为例):
- 将对象初始化为double类型值
- 将double类型值赋值给对象
- double类型值传递给接受对象参数的函数时
- 返回值为对象的函数返回double类型值时
- 在上面任意情况下,使用可转换为double类型的内置类型时
对于最后一点,函数原型化提供的参数匹配过程,允许使用构造函数来转换其他数值类型:
int a=666;
stock s1=a;
比如说上面这个,先将int类型转换为double类型,然后再使用构造函数。
不过要谨记,转换不能够存在二义性,假如还定义了:
stock(long a);
这样的构造函数,那么再有上面的int类型转换就会引发错误,因为int可以转换为long也可以转化为double。
转换函数
上面的类型转换可以把值转化为对象,那么可以把对象转换为值吗?
这就需要使用特殊的运算符函数——转换函数
转换函数是用户自定义的强制转换类型,可以像使用强制转换类型那样使用它们。
可以显示的使用也可以让编译器决定。
编译器将查找匹配的转换函数,如果没有将给出错误信息。
对于转换函数转换为typeName 的声明
operator typeName();
需要注意下面几点:
- 转换函数必须是类方法
- 转换函数不能够指定返回类型
- 转换函数不能够有参数
比如说下面的转换函数原型和定义:
operator int() const;
operator double() const;
stock::operator int() const
{
return int(value1);
}
stock::operator double() const
{
return double(value2+0.2);
}
另外需要注意,当让编译器自己选择转换函数时,不要存在有两义性的用法,否则将会报错。
比如说:
stock s1(1.4,5.6);
cout<<s1;
第二个语句将会报错,因为编译器不知道调用int和double哪一个函数。
在原则上说: 最好使用显示转换避免隐式转换。
在C++98中关键字explicit 还不能够用于转换函数,在C++11消除了这种限制,可以使用这个关键字限定转换函数以增加安全性。
也可以采用使用非转换函数替换转换函数的方法达到相同效果:
int stock::conver_to_int()
{
return int(value1);
}
用上面这个函数代替转换函数,这样,在使用转换时就必须显示的使用函数方法,而不会隐式的调用。