C++ 運算符重載,類型轉換

1、

運算符重載

規則和方法

  • 例如向四則運算符,+ - * / 原本只能用於基本類型計算,但是使用中難免會出現,類類,類基本,基本*類,像這樣的運算。
    1. 使用類成員函數重載運算符。使得該類可以使用被重載的運算符進行自定義運算,其中第一個操作符爲該類 例如:時間 + 時間,時間*n
    2. 使用友元函數重載運算符。可以實現形如 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;
}

image

  • 會發現單個輸出,沒有問題,連串輸出後會有如上錯誤。原因在於重載原型要求使用的規則是這樣的:
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;
}

image

  • 可以看出確實也是隱式進行轉換。轉換的主要點是 初始化實參和構造函數形參之間的類型轉換,內部如何轉化是用戶自定義的
  • 這種隱式轉換是可以被控制的,因爲這種轉換可能隱藏某些潛在的問題。使用關鍵字explict可以關閉這種隱式轉換。只能進行顯示轉換,也就是強制轉換。在聲明前加上explicit,如下
explicit Tree(const double h)

image
- 此時隱式調用將會報錯,編譯器找不到一個構造函數可以將 int進行轉換。

轉換函數

  • 見過可以將基本類型轉換成類的方法,是否有將類對象轉換成基本類型的方法呢?答案是有的。三點注意
    1. 轉換函數必須是類方法
    2. 轉換函數不能指定返回類型
    3. 轉換函數不能有參數
//格式如下:
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; }

image

  • 可以看到如下錯誤,這點是不難理解的,所以在多個轉換函數存在的情況下,應該顯示指明轉換目標,如下所示:
Tree tr1(5.6);
int b = tr1;
cout << "obj->int tr1: "<< double(tr1)<< endl;
cout << "obj->int  b : " << b << endl;

image

  • 和類的自動轉換類似,也可以使用explicit 限定不能進行隱式轉換,只能顯示指明轉化調用。
explicit operator double() const ;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章