流运算符和多态基类列表

时间:2017-01-14 20:15:45

标签: c++ class polymorphism

我有一个类向量,我想在屏幕上显示各自的参数。每个类都继承自CBase,而vector只是一个类型为CBase的指针列表。

我想避免将显示代码耦合到类。因此,我将流运算符放在类定义之外。

所以我的课程被定义为

class CBase 
{
public:
    virtual ~CBase(){}
};

class CChildA : public CBase
{
};

class CChildB : public CBase
{
};

并且矢量设置如下:

 void main()
{

    CChildA A;
    CChildB B;

    std::vector<CBase*> myList;
    myList.push_back(&A);
    myList.push_back(&B);

    display(myList);
}

并且各个显示操作符可能是:

std::ostream & operator<<(std::ostream & os, const CChildA & item)
{
    os << "Child A Values Here";
    return os;
}

std::ostream & operator<<(std::ostream & os, const CChildB & item)
{
    os << "Child B Values Here";
    return os;
}

要实现display函数,我们遇到了问题,因为<<不会选择正确的类,并且并非所有类都有一个流运算符定义(例如,类CChildC没有这里显示)。因此,首次展示可能是:

void display(std::vector<CBase*> &aList)
{
    for(std::vector<CBase*>::iterator it = aList.begin(); it != aList.end(); it++)
    {
        if(CChildA * ca = dynamic_cast<CChildA*>(*it))
            std::cout << *ca << "\n";
        else if(CChildB * cb = dynamic_cast<CChildB*>(*it))
            std::cout << *cb << "\n"; 
    }
}

但我被告知使用dynamic_cast不赞成。是否有一种简单的方法可以在没有dynamic_cast的情况下实现这一目标?

1 个答案:

答案 0 :(得分:1)

此时我不得不问你,

所有派生类都应该实现流操作吗?

如果对此的答案是&#39;是的&#39;或者&#39;当然!&#39;,那你为什么不把它作为界面的一部分呢?

是的,您现在可以支持将对象打印到流中。但是,你只是自己说,它是所有衍生类必须拥有的属性。

让我们想到另一个问题 -

如果我要添加新的派生类,代码中的其他位置是否会发生变化?

嗯......当然,但这些应该是微小的变化。您不想更改使用流媒体运营商的每个地方。这将违反OCP - Open Close Principle

关于这个 -

  

我想避免将显示代码耦合到类。因此,我将流运算符放在类定义之外。

你要么:

  1. 错误地假设显示应与Base
  2. 分离
  3. 发生ISP - Interface Segregation Principle违规行为。
  4. 如果每个派生类都应该是可显示的,并且持有数据的容器应该显示每个元素 - 只需将相关方法添加到Base类。

    如果你的大多数代码与显示代码无关,并且这些类确实与显示机制无关 - 每个派生类应该可以从两个接口继承(纯抽象类)

    1. Base
    2. IDisplayable(按照您的意愿命名)
    3. 您展示的展示方法应该会收到vector<IDisplayable*>而不是vector<Base*>

      注意

      如果你被迫接受vector<Base*>,你应该迭代元素并将它们转换为IDisplayable*static_castdynamic_cast,这实际上取决于你的情况)

      这与您当前的解决方案不同,因为您只需要一次演员(而不是为每个派生类设置演员表)

      <强>注2

      我不是超载“#&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&#和&#39;&gt;&gt;&#39;运营商。我会考虑一个名为&#39; display&#39;的纯虚函数。在界面而不是虚拟运算符。