2012-06-15 77 views
0

在C++中重載運算符的主要目的是什麼?在C++中重載操作符的目的是什麼?

在下面的代碼中,<<>>被重載;這樣做有什麼好處?

#include <iostream> 
#include <string> 

using namespace std; 

class book { 
    string name,gvari; 
    double cost; 
    int year; 
    public: 
    book(){}; 

    book(string a, string b, double c, int d) { a=name;b=gvari;c=cost;d=year; } 
    ~book() {} 
    double setprice(double a) { return a=cost; } 
    friend ostream& operator <<(ostream& , book&); 
    void printbook(){ 
     cout<<"wignis saxeli "<<name<<endl; 
     cout<<"wignis avtori "<<gvari<<endl; 
     cout<<"girebuleba "<<cost<<endl; 
     cout<<"weli "<<year<<endl; 
    } 
}; 

ostream& operator <<(ostream& out, book& a){ 
    out<<"wignis saxeli "<<a.name<<endl; 
    out<<"wignis avtori "<<a.gvari<<endl; 
    out<<"girebuleba "<<a.cost<<endl; 
    out<<"weli "<<a.year<<endl; 
    return out; 
} 

class library_card : public book { 
    string nomeri; 
    int raod; 
    public: 
    library_card(){}; 
    library_card(string a, int b){a=nomeri;b=raod;} 
    ~library_card() {}; 
    void printcard(){ 
     cout<<"katalogis nomeri "<<nomeri<<endl; 
     cout<<"gacemis raodenoba "<<raod<<endl; 
    } 
    friend ostream& operator <<(ostream& , library_card&); 
}; 

ostream& operator <<(ostream& out, library_card& b) { 
    out<<"katalogis nomeri "<<b.nomeri<<endl; 
    out<<"gacemis raodenoba "<<b.raod<<endl; 
    return out; 
} 


int main() { 
    book A("robizon kruno","giorgi",15,1992); 
    library_card B("910CPP",123); 
    A.printbook(); 
    B.printbook(); 
    A.setprice(15); 
    B.printbook(); 

    system("pause"); 
    return 0; 
} 
+1

簡單的答案:如果你想在控制檯中輸出一個整數值,你可以使用'std :: cout << x'。但是如果你想打印出你的類對象,除非你重載'<<'運算符,否則你不能執行'cout << ClassObj'。 – cppcoder

回答

7

它不曾被使用;這只是一種方便,讓用戶定義類型更像內置類型的方式。

例如,如果你重載運營商< <,您可以流書籍的方式整數和字符串相同:

cout << "Book #" << n << " is " << books[n] << endl; 

如果你不這樣做,你必須這樣寫一樣的東西:

cout << "Book #" << n << " is "; 
books[n].printbook(); 
cout << endl; 

同樣,如果您創建一個Fraction類,並給它的運營商+,你可以用分數你使用整數同樣的方式,等等。

無論你的類是否以某種方式行事(例如,字符串的操作符+是否合理?),它有時是一個艱難的設計選擇,但重點是C++爲您提供了選擇。

+0

所以,現在,我可以使用,例如, cout << A;在A.printbook()的s位置; 對不對? –

+0

是的。在現實生活中,你通常會用另一個來寫一個,所以它們完全相同。如果您修改printbook以採用ostream而不是硬編碼cout,那麼您的運營商可以調用a.printbook(out),並且不需要成爲朋友。 – abarnert

1

你可以很容易地使用成員函數,它只是在大多數情況下提供了「語法糖」。例如,在某些語言中,添加2個字符串會執行concat。

stringOne = stringOne + stringTwo; 

雖然它可以很容易地用一個成員函數來實現類似

stringOne.concat(stringTwo); 
2

重載<<操作允許寫出你的對象在您指定,傳遞給清點時的輸出方式。

否則,cout會將地址寫出到您的對象。

+0

它不會寫出地址:)這是一個編譯錯誤。 –

1

重載運算符允許多態的特殊情況。

我能想到的最好的例子是一個+運算符重載的字符串類。

在這種情況下,運算符將被重載以連接字符串,而不是「添加」兩個沒有任何意義的字符串。

要回答你的問題,特別是重載操作符可以(在某些情況下)生成更具可讀性和可維護性的代碼。然而,對於一個人來說「有意義」對維護代碼的人來說可能沒有意義。

0

重載< <和>>操作符的主要目的是根據C++標準庫的精神創建API,因此對於有經驗的C++程序員來說,使用類型更自然。

當與STL流一起使用時,運營商< <和>>被稱爲insertion/extraction operators。從C他們只是bit shift operators

由於在標準C的境界++,他們獲得了這個含義,甚至獲得了新的命名爲,這是很好的跳投再利用已經建立的編程術語。

現在,原來在C++創建的,爲什麼它已經這樣的流操作?通過獲得換班操作員並將他們標記爲插入和提取操作員,我不知道,考慮到換班操作員的出現,我可能不知道,可以更好地表達插入/提取的想法,這是現在已經成爲標準的含義並適合重用。

1

隨着重載運算符,你可以使用標準庫算法,它要求運營商超載。

例如:

struct wtf{ wtf(int omg): omg(omg){} int omg; }; 

wtf operator+ (wtf const &omg, wtf const &lol) 
{ 
    return wtf(omg.omg+ lol.omg); 
} 

#include <iostream> 
#include <numeric> 

int main() 
{ 
    wtf lol[3]= { wtf(1), wtf(2), wtf(3) }; 
    std::cout<< std::accumulate(lol, lol+ 3, wtf(0)).omg; 
} 
+1

+1,因爲這是其他答案(包括我的)沒有涵蓋的一點。你可以說這僅僅是一種「像本土類型一樣工作」的特殊情況,但這是一個非常特殊和重要的案例。 – abarnert

1

約C++是它傳遞的東西對象由值,因爲它是如何工作的一個基本目標,這確實大大改變與Java和Objective-C等面向參考語義的語言相比,對象是如何工作的。

鑑於其中一種語言在基本類型和對象之間就使用方式而言存在明顯的區別 - 也就是說,您複製原語很多,您將它們粘貼到涉及運算符的表達式中,而你與對象的交互主要是實例化它們,調用它們的方法並將它們的引用傳遞給函數 - 在C++中,你可以像使用基元一樣使用對象。這帶來了大量的該C++程序員不得不處理,就像對象生存複雜的問題,一個對象是否是一個左值或右值(即,如果它有它出現在表達外的壽命)等

有一件事你的問題帶來了就是一類會超載< <和>>。 C++標準庫使用此約定的iostream班,並強調基於語言參考語義學上的又一大區別 - 面向語言的值語義,類繼承是不夠全面地描述你想要的目的是做什麼。我們可以寬鬆地說,如果一個對象超載了< <和>>來流入和流出某個資源的數據,那麼它滿足iostream的概念,即使它不從iostream或ios_base繼承,或者一些東西。這樣做的意義是雙重的:

  1. 如果你把這種類型的到表達和使用< <,它會像預期的那樣。
  2. 如果實例化一個模板,並將此類型作爲參數調用操作對象上的運算符<,代碼將成功編譯。

我故意用這個詞概念上面,因爲是要在C++ 11(它得到順延到下一版本)稱爲概念功能這將正式這種想法的語言。我們現在的情況是一種duck typing - 如果一個模板想要使用某個類型的操作符,它將在該類型提供該操作符時進行編譯,如果該操作符不是,則不進行編譯操作員實際上意味着。運算符< <就其實際意義而言,對於整數類型而言,它表示「向左簽名的位移」,但是當您使用iostream的概念時,它意味着「來自右側對象的流數據進入左邊的對象「。

2

重載操作符的目的主要是語法糖。它使醜陋的東西看起來不錯。但它也是關於統一接口的,統一接口的一個重要原因是多態,在這種情況下尤其是模板。

想象一下,我們有一個可愛的複數類Complex,我們希望有一個泰勒級數的正弦逼近,我們想要使複雜和雙類型的工作。

如果我們支持操作符重載上*=/等等,那麼我們可以寫這樣的:

template<typename T> 
T sin(T t) 
{ 
    T t2 = t*t; 
    return t*(1 - t2/6 + (t2*t2)/120); 
} 

如果我們不能對超載*/等,然後它開始變得難看,因爲我們需要一個幫助類來統一雙打和複合的界面,所以它可能看起來像什麼。 (我仍然允許operator=超載,否則會變得更糟)。

template<typename T> 
T sin(T t) 
{ 
    T t2 = helper<T>::mult(t, t); 
    T t4 = helper<T>::mult(t2, t2); 
    T s(1); 
    helper<T>::sincrement(&s, -1./6, t2); 
    helper<T>::sincrement(&s, -1./120, t4); 
    return helper<T>::mult(t, s); 
} 

template<> 
struct helper<double> 
{ 
    static double mult(double a, double b) { return a*b; } 
    static void sincrement(double * v, double s, double x) { *v += s*x; } 
} 

template<> 
struct helper<Complex> 
{ 
    static Complex mult(Complex a, Complex b) { return a.mult(b); } 
    static void sincrement(Complex * v, double s, Complex x) { v->add(x.scale(s)); } 
} 

現在我知道運算符重載可以醜,並且可以隱藏什麼是真正發生的事情,但正確的使用,我認爲,它使這樣的情況下,更容易理解。