2012-07-21 68 views
2

有一個類A具有虛擬方法print()和重載操作符< <定義爲朋友函數。C++:Operator <<在派生類中使用默認參數?

#include <iostream> 
class A 
{ 
public: 
    double a1, a2; 
    A(): a1(10.0), a2(10.0) {} 

    virtual void print (std::ostream * o = &std::cout) const 
    { 
     *o << a1<< '\t' << a2 << '\n'; 
     } 

    friend std::ostream & operator << (std::ostream & o, const A &aa) 
    { 
     o << aa.a1 << '\t' << aa.a2 << '\n'; 
     return o; 
    } 
}; 

和類似的派生B類

class B : public A 
{ 
public: 
    double b1, b2; 
    B(): A(), b1(20.0), b2(20.0) {} 

    virtual void print (std::ostream * o = &std::cout) const 
    { 
     A::print (o); 
     *o << b1<< '\t' << b2; 
    } 

    friend std::ostream & operator << (std::ostream & o, const B &bb) 
    { 
     o << (A)(bb); 
     o << bb.b1 << '\t' << bb.b2 << '\n'; 
     return o; 
    } 
}; 

我有以下問題:

1]有什麼辦法如何將指針傳遞給ostream的默認參數對象,從而運營商< <正確替換print()方法?這個超載是錯誤的

friend std::ostream & operator << (std::ostream * o= &std::cout, const A &aa) 

2]我不確定,如果這行調用派生類B中父類A的運算符是正確的?

o << (A)(bb); 

3]有沒有更好的辦法如何重載操作< <沒有「朋友」宣言?

感謝您的幫助....

+1

當'operator <<'可以簡單地調用'print'時,爲什麼要在'operator <<'中複製'print'的功能?然後你只需要一個'operator <<(ostream&,const Base&)',它可以用於完整的層次結構。 – pmr 2012-07-21 20:24:33

回答

1

你可以像下面這樣做沒有友誼:

#include <iostream> 
class A 
{ 
    double a1, a2; 

public: 
    A(): a1(10.0), a2(10.0) {} 

    virtual void print (std::ostream * o = &std::cout) const 
    { 
     *o << a1 << '\t' << a2; 
    } 
}; 

std::ostream & operator << (std::ostream & o, const A &aa) 
{ 
    o << "()"; 
    aa.print(&o); 
    return o << ")"; 
} 

然後class B沒有的operator<<一個單獨的版本,這將是一個發現,並在通過B實例時調用B::print

+0

爲了一致性,我還建議打印使用引用而不是指針。這也可以讓你避免處理指針所需的額外操作符。 – 2012-07-21 19:35:57

+0

@ Code-Guru:我保持它與問題中使用的簽名兼容,因爲沒有改變它的強制性理由。 – 2012-07-21 20:02:01

+0

好點。對於它的價值,我的評論更多的是OP,而不是你作爲回答者。我可能應該爲他添加@標記。 – 2012-07-21 20:57:24

1

我一直想知道如何避免冗長的朋友聲明,並提出以下幾點:

template<typename T> 
class OutEnabled { 
    public: 
    friend std::ostream& operator<<(std::ostream& out, T const& val) { 
     return static_cast<OutEnabled<T> const&>(val).ioprint(out); 
    } 

    friend QTextStream& operator<<(QTextStream& out, T const& val) { 
     return static_cast<OutEnabled<T> const&>(val).ioprint(out); 
    } 

    friend QDebug operator<<(QDebug dbg,T const& val) { 
     std::stringstream myStream; 
     myStream << val; 
     dbg.maybeSpace() << myStream.str().c_str(); 
     return dbg; 
    } 

    protected: 
    template<typename U> 
    U& ioprint(U& out) const { 
     return static_cast<T const*>(this)->print(out); 
    } 
}; 

class Foo:public OutEnabled<Foo>{ 
    public: 
    Foo(){} 

    template<typename V> 
    V& print(V& out) const{return out<< "Bar";} 
}; 

寫這個,我可以這樣寫:

std::cout << Foo(); 
qDebug() << Foo(); 

...

我使用這個概念很多,因爲它允許您指定一個打印並將其用於不同的流。我必須至少使用我提到的三個,所以對我來說這是值得的複雜性。朋友不在你的班級,所以少打字,從繼承中可以看出你的班級是可打印的。微小的缺點是你在每個使用OutEnabled的類中都有一個模板。

相關問題