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 ;