1、
运算符重载
规则和方法
- 例如向四则运算符,+ - * / 原本只能用于基本类型计算,但是使用中难免会出现,类类,类基本,基本*类,像这样的运算。
- 使用类成员函数重载运算符。使得该类可以使用被重载的运算符进行自定义运算,其中第一个操作符为该类 例如:时间 + 时间,时间*n
- 使用友元函数重载运算符。可以实现形如 n*时间 的计算,需要在类中的声明前 加上 friend 表明是友元,在类外部实现友元函数无需使用friend。在友元函数中可以访问类中的私有成员。
class Time
{
private :
int hours;
int minutes;
public :
Time(int h, int m){ hours = h; minutes = m; }
Time() {};
void showTime()
{
cout << "Time :" << hours << " : " << minutes << endl;
}
Time operator + (const Time & ) const;
Time operator * (const int & )const;
friend Time operator *(const int & n, const Time &t);
};
Time Time::operator + (const Time & t) const
{
Time sum;
sum.minutes = minutes + t.minutes;
sum.hours = hours + t.hours + sum.minutes / 60;
sum.minutes %= 60;
return sum;
}
Time Time::operator*(const int & n) const{
Time t;
t.minutes = minutes*n % 60;
t.hours = hours*n %24 + minutes*n/ 60;
cout << "调用1" << endl;
return t;
}
Time operator *(const int &n, const Time & t)
{
Time mul;
mul.minutes = (t.minutes )* n % 60;
mul.hours =( t.hours) * n %24 +t.minutes*n / 60;
cout << "调用2" << endl;
return mul;
}
int main()
{
Time a = { 5, 20 };
Time b = { 3, 10 };
Time c = a + b;
Time d = b * 7;
d.showTime();
Time e = 7 * b;
e.showTime();
cin.get();
return 0;
}
- 重载运算符 <<比较特殊,可以如下实现
void operator << (ostream & os, const Time & t)
{
os << t.hours << " : " << t.minutes << endl;
}
- 会发现单个输出,没有问题,连串输出后会有如上错误。原因在于重载原型要求使用的规则是这样的:
ostream << Time //然而,分解 cout <<e <<d;实际上是
void(ostream <<Time) << Time; //所以问题在于返回值。
改为如下:
ostream & operator << (ostream & os, const Time & t)
{
os << t.hours << " : " << t.minutes << endl;
return os;
}
类的自动类型转换和强制转换
- 在基本类型的使用中常常见到的规则就是类型转换。如果右值类型与左值类型不匹配,若是各种兼容的数值类型,则可以隐式转换成左值类型。如下:
long count =8;
double time 11;
int side =3.33;
- 在类的使用过程中有一个特点,编译器会自动根据初始化类型调用相应的构造函数。基于自动调用和基本类型自动转换的特点形成了 类的自动类型转换。有如下测试:
class Tree{
private :
double height;
public:
Tree(){}
Tree(const double h) {
height = h;
cout << "调用构造 height:"<<h << endl; }
};
int main()
{
Tree tr1;
int a = 5;
tr1 = a;
cin.get();
return 0;
}
- 可以看出确实也是隐式进行转换。转换的主要点是 初始化实参和构造函数形参之间的类型转换,内部如何转化是用户自定义的
- 这种隐式转换是可以被控制的,因为这种转换可能隐藏某些潜在的问题。使用关键字explict可以关闭这种隐式转换。只能进行显示转换,也就是强制转换。在声明前加上explicit,如下
explicit Tree(const double h)
- 此时隐式调用将会报错,编译器找不到一个构造函数可以将 int进行转换。
转换函数
- 见过可以将基本类型转换成类的方法,是否有将类对象转换成基本类型的方法呢?答案是有的。三点注意
- 转换函数必须是类方法
- 转换函数不能指定返回类型
- 转换函数不能有参数
//格式如下:
operator int(){ return height; }
测试代码:
class Tree{
private :
double height;
public:
Tree(){}
Tree(const double h) { height = h; }
operator int(){ return height; }
};
int main()
{
Tree tr1(5);
int b = tr1;
cout << "obj->int tr1: "<< tr1<< endl;
cout << "obj->int b : " << b << endl;
cin.get();
return 0;
}
- 可以看出,对象根据自定义的转换函数转成了相应的基本类型。当要输出对象时,编译器可以自动选择唯一的准换函数,编译器只有唯一选择。然而如果还有其他选择,例如:
public:
Tree(){}
Tree(const double h) { height = h; }
operator int(){ return height; }
operator double(){ return height; }
- 可以看到如下错误,这点是不难理解的,所以在多个转换函数存在的情况下,应该显示指明转换目标,如下所示:
Tree tr1(5.6);
int b = tr1;
cout << "obj->int tr1: "<< double(tr1)<< endl;
cout << "obj->int b : " << b << endl;
- 和类的自动转换类似,也可以使用explicit 限定不能进行隐式转换,只能显示指明转化调用。
explicit operator double() const ;