2011-10-07 86 views
8

我有一個基類,然後有幾個派生類。我想重載這些派生類的「< <」運算符。對於正常的操作符,即'+',虛擬函數可以做到這一點。我所理解的標準約定是在我的類中聲明重載<<運算符和繼承類

friend ostream& operator<<(ostream& out, MyClass& A); 

然後在類之後定義函數。先驗,我會認爲虛擬以上定義將使它的工作,但經過一些想法(和我的編譯器的錯誤),我意識到這沒有多大意義。

我在一個測試用例上嘗試了一個不同的方法,其中所有的類成員都是公開的。例如:

class Foo{ 
//bla 
}; 

ostream& operator<<(ostream& out, Foo& foo){ 
    cout << "Foo" << endl; 
    return foo; 
} 

class Bar : public Foo{ 
//bla 
}; 

ostream& operator<<(ostream& out, Bar& bar){ 
    cout << "Bar" << endl; 
    return bar; 
} 

/////////////////////// 

Bar bar = Bar(); 
cout << bar << endl; // outputs 'Foo', not 'Bar' 

因此,在某種程度上這是「多態變壞」 - 基類的運營商< <被調用,而不是派生類的運營商。在上面的例子中,我如何讓派生類調用正確的操作符?更一般地說,如果我的班級有我想要保護的私人成員,那麼如何在使用friend關鍵字時更正操作員重載?

回答

6

您可以使用虛擬助手功能。這裏是一個完全未經測試的例子,所以請原諒任何語法錯誤:

virtual ostream& Foo::print(ostream& out) const { 
    return out << "Foo"; 
} 

virtual ostream& Bar::print(ostream& out) const { 
    return out << "Bar"; 
} 

// If print is public, this doesn't need to be a friend. 
ostream& operator<<(ostream& out, const Foo& foo) { 
    return foo.print(out); 
} 

編輯:每@Omnifarious建議清理。

+0

完美地工作。謝謝。 – andyInCambridge

+0

我認爲這有兩個缺陷。一個缺陷是一個巨大的缺陷,另一個缺陷是一個小缺陷。首先是巨大的缺陷......你永遠不應該無形地投入'endl'。 'endl'強制刷新流,在某些情況下這可能是一個很大的性能問題。使用''\ n''。它保證了一樣的可移植性(實際上,'endl'是根據輸出''\ n''的方式定義的,並且不會產生刷新開銷。其次,我會這樣做:'return out <<「Foo \ n「;'感覺稍微乾淨一點,它在概念上將整個事情變成一個長操作鏈' – Omnifarious

+0

@Omnifarious我永遠不會把'endl'放在'operator <<'overload中,我只是在OP的代碼 –

2

通常,您只需在由單個免費好友函數調用的基類中創建一個多態的print方法。

+0

如果印刷品是公開的,那麼我們可以將這位朋友拋棄。 –

+0

好點,謝謝。 – andyInCambridge

1

通過正確的代碼更正,您的代碼工作正常;無計可施

ostream& operator<<(ostream& out, Foo& foo) { 
    out << "Foo" << endl; // 'out' and not 'cout' 
    return out; // returns 'out' and not 'foo' 
} 

ostream& operator<<(ostream& out, Bar& bar) { 
    out << "Bar" << endl; // 'out' and not 'cout' 
    return out; // returns 'out' and not 'bar' 
} 

Demo。要訪問private成員,您可以在所需的class中將此功能設爲friend

+1

有趣。在我的實際代碼中,我正確地使用了而不是cout,但它仍然無法工作。必須有一些細微的東西不會被填充類/ bla類捕獲。 – andyInCambridge