2013-02-14 50 views
1

我正在實施printing pattern for a class hierarchy,如C++ FAQ中所述。在FAQ中,打印功能是在基類中這樣聲明:C++中的類層次結構打印模式常見問題解答

protected: 
    virtual void printOn(std::ostream& o) const = 0; // pure virtual 
    // -- or -- 
    virtual void printOn(std::ostream& o) const;  // plain virtual 

我正在考慮實施printOn方法,但有一個變化的純虛擬版本。我想從void返回類型更改爲std::ostream&如下所示:

protected: 
    virtual std::ostream& printOn(std::ostream& o) const; 

這種方法,因爲我看到它是允許一個基類的輸出的優勢更容易被摻入的派生類使用鏈接方法。這裏有一個例子:

std::ostream& DerivedClass::printOn(std::ostream& stream) const 
{ 
    return stream 
     << "<DerivedClass>" << '\n' 
     << BaseClass::printOn(stream) 
     << "<member_one>" << member_one_ << "</member_one>" << '\n' 
     << "<member_two>" << member_two_ << "</member_two>" << '\n' 
     << "</DerivedClass>" << std::endl; 
} 

相反,這裏如果虛擬BaseClass::printOn方法聲明voidDerivedClass::printOn會是什麼樣如圖所示FAQ:

void DerivedClass::printOn(std::ostream& stream) const 
{ 
    stream << "<DerivedClass>" << '\n'; 
    BaseClass::printOn(stream); 

    stream 
     << "<member_one>" << member_one_ << "</member_one>" << '\n' 
     << "<member_two>" << member_two_ << "</member_two>" << '\n' 
     << "</DerivedClass>" << std::endl; 
} 

 

問題:不任何人看到我提出的修改printOn返回類型的任何陷阱?

回答

2

如果BaseClass::printOn(stream)返回std::ostream &那麼你可以不寫

stream << ... << BaseClass::printOn(stream) << ...; 

你不得不寫:

stream << ...; 
BaseClass::printOn(stream) << ...; 

顯然,這幾乎比任何情況下更好地在那裏返回void 。你可以返回一個類型與無操作流進行操作:

struct noop_manipulator { 
    noop_manipulator(std::ostream &) {} 
    friend inline std::ostream &operator<<(std::ostream &os, const noop_manipulator &) { 
    return os; 
    } 
}; 

noop_manipulator DerivedClass::printOn(std::ostream& stream) const 
{ 
    return stream << ...; 
} 

或者,你可以玩的語法:

void DerivedClass::printOn(std::ostream& stream) const 
{ 
    return stream << "<DerivedClass>" << '\n', 
     BaseClass::printOn(stream), stream 
     << "<member_one>" << member_one_ << "</member_one>" << '\n' 
     << "<member_two>" << member_two_ << "</member_two>" << '\n' 
     << "</DerivedClass>" << std::endl; 
} 

的缺點所有這些方法是,它們遮住了使用超類虛擬呼叫,這是非常不尋常的,它應該儘可能清晰。所描述的印刷圖案本身相當不尋常;除非已有虛擬繼承層次結構,否則派生類通常具有其自己的operator<<,並且通過static_cast將基類operator<<稱爲基類引用。

+0

@DavidRR在語法上你調用'ostream << ostream',它沒有特別定義,但通常會調用'operator void *'fail-check操作符。您應該期望在輸出流中看到一個指針值。 – ecatmur 2013-02-14 22:25:01

+0

是的,在我實際建立了我提出的原型之後,它確實變得清楚,我最終調用了'ostream << ostream'。而且我現在確實正在從頭開始開發虛擬繼承層次結構,並且我認爲C++ FAQ建議的印刷模式非常合適。我也會記住你推薦的替代方法來在派生類中重載'operator <<'。 – DavidRR 2013-02-19 14:05:12