流运算符和多态基类列表



我有一个类向量,我想在屏幕上显示它们各自的参数。每个类都继承自CBase,并且向量只是类型为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. 错误地认为显示器应与底座解耦
  2. 收到一个违反ISP接口隔离原则的问题

如果每个派生类都应该是可显示的,并且保存数据的容器应该显示每个元素,那么只需将相关方法添加到基类中即可。

如果你的大部分代码与显示代码无关,而这些类确实与显示机制无关——每个派生类可能都应该继承自两个接口(纯抽象类)

  1. Base
  2. IDisplayable(按您的意愿命名)

并且您显示的显示方法应该接收vector<IDisplayable*>而不是vector<Base*>

注意

如果您被迫使用vector<Base*>,则应该迭代元素并将其强制转换为IDisplayable*(static_castdynamic_cast,这实际上取决于您的情况)

这与您当前的解决方案不同,因为您只需要一个类型转换(而不是每个派生类都有一个类型)

注2

我不太喜欢重载'<lt;'和">>"运算符。我会考虑在界面中使用一个名为"display"的纯虚拟函数,而不是虚拟运算符。

最新更新