重载std :: ostream&运营商LT;<在没有static_cast<>的派生类中

时间:2012-05-23 18:30:02

标签: c++

这是为派生类重载ostream& operator<<而不重复基类代码的唯一方法吗?演员阵容不是要避免的吗?

我没有看到任何其他方式,除了在基类中定义某种类型的函数,它将表示基类的数据作为std :: operator&lt;&lt;可以“吃掉”(像一个字符串?),为派生类做同样的事情(在派生类流中调用基类流表示函数。当然是rep。函数)。

这个问题的理想解决方案是什么?

#include <iostream>

class Base
{
    private: 
        int b_;
    public: 
        Base()
            :
                b_()
        {};

        Base (int b)
            : 
                b_(b)
        {};

        friend std::ostream& operator<<(std::ostream& os, const Base& b);
};

std::ostream& operator<< (std::ostream& os, const Base& b)
{
    os << b.b_; 
    return os;
}

class Derived
:
    public Base
{
    private: 
        int d_;
    public: 
        Derived()
            :
                d_()
        {};

        Derived (int b, int d)
            : 
                Base(b), 
                d_(d)
        {};

        friend std::ostream& operator<<(std::ostream& os, const Derived& b);
};

std::ostream& operator<< (std::ostream& os, const Derived& b)
{
    os << static_cast<const Base&>(b) << " " << b.d_; 
    return os;
}



using namespace std;


int main(int argc, const char *argv[])
{
    Base b(4);

    cout << b << endl;

    Derived d(4,5);

    cout << d << endl;

    return 0;
}

4 个答案:

答案 0 :(得分:6)

嗯......如果在没有正确定义结果的情况下进行投射,应该避免投射,但是投射到底座总是安全的。

可以通过考虑派生引用衰减到基本引用来避免显式转换,因此您可以使用隐式转换,如下例所示:

std::ostream& operator<< (std::ostream& os, const Derived& b)
{
    const Base& bs = b;
    os << bs << " " << b.d_; 
    return os;
}

答案 1 :(得分:5)

static_cast<const Base&>(b)

是安全的,并且没有任何错误,因为每个派生类对象也是一个Base类对象,可以像对待一样对待。

仅在以鲁莽的方式使用时,演员才是危险的,你必须在需要的时候以正确的方式使用演员表,这是他们按照语言标准提供的目的。

答案 2 :(得分:1)

你可以改变这样的事情:

struct Base {
    int b_;
    void print(ostream &o) { o << b_; }
};

struct Derived : Base {
    int d_;
    void print(ostream &o) {
        Base::print(o);
        o << ' ' << d_;
   }
};

ostream &operator<<(ostream &o, Base &b) {
    b.print(o);
    return o;
}

ostream &operator<<(ostream &o, Derived &d) {
    d.print(o);
    return o;
}

如果Base有虚函数(在本例中没有),则print可能就是其中之一,你可以摆脱operator<<的多重载荷

答案 3 :(得分:1)

如果您不喜欢演员表,您可以让您的操作员调用使用模板方法模式实现的writeTo函数。

e.g。

class Base {
   public:
       std::ostream& writeTo(std::ostream& ostr) const { os << b_; return this->doWriteTo(os); }
   private:
       int b_;

       virtual std::ostream& doWriteTo(std::ostream& ostr) const = 0; // pure virtual
};


class Derived {
    private:
        int d_;
        virtual std::ostream& doWriteTo(std::ostream& ostr) const {return ostr << d_;}
};

std::ostream& operator<<(std::ostream& ostr, const Derived& d) {
  return d.writeTo(ostr);

}

实际上,使用此模式,您可以为operator<<一劳永逸地写Base

std::ostream& operator<<(std::ostream& ostr, const Base& b) {
  return b.writeTo(ostr);

}

此模式也消除了将operator<<设为friend的需要。