重载'<<'继承和多态?

时间:2012-08-10 16:24:39

标签: c++ inheritance polymorphism operator-overloading

以下是代码外观的粗略示例,问题是如何让DerivedOne和DerivedTwo重载<<运算符,但将这些对象存储在Base *。

的向量中

至于我想要达到的目标;我希望能够遍历对象向量并输出我在DerivedOne和DerivedTwo中告诉它的信息。

vector<Base*> objects;

class Base
{
 private:
 object Data
 public:
 object getData() { return Data; }
};

class DerivedOne : public Base
{
}

class DerivedTwo : public Base
{
}

现在我知道有这个,但它不能用于我的目的。

friend ostream &operator<<(ostream &stream, Object object)
{
    return stream << "Test" << endl;
}

3 个答案:

答案 0 :(得分:12)

Make your virtual methods private to separate how an object is used from how its behavior can be customized by derived classes.

这与其他答案解决方案类似,但虚拟方法是私有的:

#include <iostream>

namespace {
  class Base {
    // private (there is no need to call it in subclasses)
    virtual std::ostream& doprint(std::ostream&) const = 0;
  public:
    friend std::ostream& operator << (std::ostream& os, const Base& b) {
      return b.doprint(os); // polymorphic print via reference
    }

    virtual ~Base() {} // allow polymorphic delete
  };


  class DerivedOne : public Base {
    std::ostream& doprint(std::ostream& os) const {
      return os << "One";
    }
  public:
    DerivedOne() { std::cerr << "hi " << *this << "\n"; } // use << inside class
    ~DerivedOne() { std::cerr << "bye " << *this << "\n"; }
  };
}

实施例

#include <memory>
#include <vector>

int main () {
  using namespace std;
  // wrap Base* with shared_ptr<> to put it in a vector
  vector<shared_ptr<Base>> v{ make_shared<DerivedOne>() };
  for (auto i: v) cout << *i << " ";
  cout << endl;
}

输出

hi One
One 
bye One

答案 1 :(得分:5)

您可以这样做:

struct Base {
    virtual ~Base () {}
    virtual std::ostream & output (std::ostream &) const = 0;
};

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

然后,在operator<<上应用Base时,它将调用派生输出方法。

答案 2 :(得分:2)

到目前为止,您的问题已经描述,您有一组动态分配的多态对象。

解决方案可能会根据这些对象如何遵守某些设计原则而发生变化:

  1. 你反对“只有叶子的物体”吗? (不是指其他对象本身)?
  2. 是否只有单个非循环引用(您的对象是否仅形成子对象的树)?
  3. 引用之间有多条路径(由两个或更多个引用的同一个对象)
  4. 有循环参考吗?
  5. 是否有对其他对象成员的引用
  6. 根据情况,情况会变得非常复杂,并且取决于您是否可以容忍同一个对象的多个输出,以及如何打破最终的循环。

    你不能做的第一件事就是使用Base作为一个值参数(就像在你身上一样,因为它会创建一个副本(承认你的对象是可复制的:如果他们引用其他对象,副本会做什么?路径?克隆引用的对象?)

    如果你处于情境(1.),你只需要一个虚拟函数std::ostream&,在所有叶对象中被覆盖。然后,您需要operator<<(std::ostream&, Base*)的重载和(std::ostream&, const std::vector<Base*>&)

    的重载 像这样:

    class Base
    {
        ...
    public:
        virtual ~Base() {} //must be polymorphic
    protected:
        virtual void out(std::ostream& s) =0;
    
        friend std::ostream& operator<<(std::ostream& st, Base* pb)
        { pb->out(st); return st; }
    };
    
    class Derived1: public Base
    {
        ...
    protected:
        virtual void out(std::ostream& s)
        {
            s << "Derived1 at " << this << " address " << std::endl;
        }
    };
    
    
    class Derived2: public Base
    {
        ...
    protected:
        virtual void out(std::ostream& s)
        {
            s << "Derived2 at " << this << " address " << std::endl;
        }
    };
    
    std::ostream& operator<<(std::ostream& s, const std::vector<Base*>& v)
    {
        s << "there are " << v.size() << " objects:" << std::endl;
        for(auto& i:v)
            s << i;
        return s;
    }
    

    如果你在sutuation(2.)yopu可能ave a

    class Derived3: public Base
    {
        ...
        Base* ptrOwnedobject;
    };
    

    您可以简单地实施Derived3::out功能以追索自己的孩子。

    如果您处于情境(3.),并且您不能容忍相同的对象被打印更多时间,您不同的父母共享同一个孩子。你应该以某种方式标记孩子,这样你就不会将它保存两次或更多次,并在完成打印后取消所有孩子的标记(你很可能会将这种机制设置到Base类中)。

    如果您处于情境(4.),那么关于(3.)的说法必须成为避免无限递归的必要条件。

    如果您处于情境(5.),您还必须发现成员所属的对象(非常简单)。如果你还有多个继承和虚拟基础......事情就更复杂了。