在前面我们学习了关于类的一些基本使用,下面我们更深入的学习使用类。这里包含了下面几个内容:
1:操作符重载
2:友员
3:类的转换
操作符重载:使我们对类型使用+、-等常用操作符。要重载操作符,需使用称为运算符函数的特殊函数,它的形式如下:
operator op(argument-list) ; op 可以是+、-、*、/等操作符,argument-list 是参数列表
下面创建一个两个时间相加的+操作符:
#include<iostream> using namespace std ; class Time{ private : int hour , minute , second ; public : Time(int hour , int minute , int second) ; Time() {} //默认构造函数 Time operator+(const Time &t) const ; void show()const ; } ; int main(){ Time t1(3 , 20 , 30) ; Time t2(4 , 30 , 10) ; cout << "t1 : \n" ; t1.show() ; cout << "t2 : \n" ; t2.show() ; Time t3 = t1 + t2 ;
cout << "t3 : \n" ; t3.show() ; return 0 ; } Time::Time(int hour , int minute , int second){ this->hour = hour ; this->minute = minute ; this->second = second ; } Time Time::operator+(const Time &t) const { Time sum ; //使用默认构造函数 sum.second = second + t.second ; sum.minute = minute + t.minute + sum.second/60 ; sum.hour = hour + t.hour + sum.minute/60 ; sum.second %= 60 ; sum.minute %= 60 ; sum.hour %= 24 ; return sum ; } void Time::show()const { cout << "hour : " << hour << " minute : " << minute << " second : " << second << endl ; }
Time t3 = t1 + t2 ; 使用重载+操作符 ,运算符右边的值是作为参数传递来的, Time t3 = t1.operator+(t2) ; 这样使用也可以
重载运算符不是一定是成员函数,也可以是非成员函数,但必须至少有一个操作数是用户定义的类型。如:
#include<iostream> using namespace std ;
class Time{ private : int hour , minute , second ; public : Time(int hour , int minute , int second) ; Time() {} //默认构造函数 Time operator+(const Time &t) const ; //友元函数 在函数中可以直接使用该类的私有成员 friend Time operator+(int h , const Time &t ) ; friend Time operator+(const Time &t , int h ) ; void show()const ; } ; int main(){ Time t1(3 , 20 , 30) ; Time t2(4 , 30 , 10) ; cout << "t1 : \n" ; t1.show() ; cout << "t2 : \n" ; t2.show() ; //重载操作符作为成员函数时,对象必须在操作符的左边 Time t3 = t1 + t2 ; cout << "t3 : \n" ; t3.show() ; //重载操作符作为非成员函数时,第一个参数在左边,第二个在右边 Time t4 = t1 + 5 ; cout << "t4 : \n" ; t4.show() ; Time t5 = 5 + t1 ; cout << "t5 : \n" ; t5.show() ; return 0 ; } Time::Time(int hour , int minute , int second){ this->hour = hour ; this->minute = minute ; this->second = second ; } Time Time::operator+(const Time &t) const { Time sum ; //使用默认构造函数 sum.second = second + t.second ; sum.minute = minute + t.minute + sum.second/60 ; sum.hour = hour + t.hour + sum.minute/60 ; sum.second %= 60 ; sum.minute %= 60 ; sum.hour %= 24 ; return sum ; } void Time::show()const { cout << "hour : " << hour << " minute : " << minute << " second : " << second << endl ; } //非成员函数 Time operator+(int h , const Time &t ) { Time sum ; sum.hour = (sum.hour + h)%24 ; return sum ; } Time operator+(const Time &t , int h ) { Time sum ; sum.hour = (sum.hour + h)%24 ; return sum ; }
操作符重载的使用形式都同+操作符重载差不多,根据操作符的实际意义来判断返回值。
友元:c++控制对类对象私有成员的访问,外界只能通过公有方法来访问,若外界也想使用类对象的私有成员,则我们可以将他们设置为类的友元,友元可以访问类对象的私有成员。
友元有三种:
友元函数:将函数设置为类的友元,则在函数中可以访问类的所有成员(包含私有成员)。
友元类 :将类person设置为类Time的友元,则类person的成员函数可以访问类Time的所有成员(包含私有成员)。
友元成员函数:将类person的成员函数setPerson()成员函数设置为类Time的友元,则在成员函数setPerson中可以访问类Time的所有成员(包含私有成员)。
创建友元函数:将函数的声明放在类的声明中,前面加关键字friend,如:
friend Time operator+(int h , const Time &t ) ;
虽然,函数是在类声明中声明的,但它不是成员函数,虽然不是成员函数,但它与成员函数有相同的访问权限。
编写函数定义时,它不是成员函数,不用在Time::限定符,另外,不用再定义总是用friend关键字。
Time operator+(int h , const Time &t ) { Time sum ; sum.hour = (sum.hour + h)%24 ; return sum ; }
大部分重载运算符既可以用成员函数实现,也可以使用非成员函数实现,非成员函数应该是友元函数,否则不能访问类的私有数据,成员函数的第一个操作数是用this隐性传递的,非成员函数的所有操作数都是函数的参数,操作数的位置是根据参数的位置来定的。
友元类:
#include<iostream> using namespace std ; class Ta ; class Tc { public :
/*class Ta在class Tc之前声明,可以使用Ta类名,不能使用类Ta的数据成员和成员函数,
因为编译器不知道,如果该函数在这里实现就会出错,不知道ta.a
*/
void changeA(Ta &ta) ;
} ; class Ta { int a ; public : friend class Tb ; //友元类 在这里也声明了Tb,Ta知道了类名Tb friend void Tc::changeA(Ta &ta) ; //友元成员函数 因为Tc>声明在Ta之前,这里可以使用Tc::changeA(Ta &ta); 函数声明 Ta(int i) { a = i ; } int getA(){ return a ; } }; class Tb { public : void changeA(Ta &ta) { ta.a += 10 ; //可以访问Ta的私有成员 } } ; void Tc::changeA(Ta &ta) { //不能放在Tc类中实现,因为不能使用ta.a ta.a += 20 ; } int main(){ Ta ta(10) ; cout << "before : a : " << ta.getA() << endl ; Tb tb ; tb.changeA(ta) ; cout << "now : a : " << ta.getA() << endl ; return 0 ; }
要先声明,才能够使用。因为Tc类中在Ta声明之前就使用了Ta类名,则我们应该使用class Ta声明Ta类名,因为Ta的成员还没有声明,所以在Tc类中不能使用Ta的数据成员ta.a, 这个我们应该好好理解下。
类的自动转换和强制转换: