我有一个类向量,我想在屏幕上显示它们各自的参数。每个类都继承自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
,有没有一种简单的方法可以实现这一点?
在这一点上,我必须问你,
您的所有派生类都应该实现流操作吗
如果答案是"是"或"当然!",那你为什么不把它作为你界面的一部分呢?
是的,您现在支持将对象打印到流中。但是,您刚才自己说过,这是所有派生类都必须具有的属性。
让我们想想另一个问题——
如果我应该添加一个新的派生类,代码中的其他位置是否应该更改
嗯。。。当然,但这些应该是小改动。你不想改变每一个使用流媒体运营商的地方。这将违反开放-关闭原则。
关于此-
我希望避免将显示代码耦合到类。因此,我将流运算符放在类定义之外。
您可以:
- 错误地认为显示器应与底座解耦
- 收到一个违反ISP接口隔离原则的问题
如果每个派生类都应该是可显示的,并且保存数据的容器应该显示每个元素,那么只需将相关方法添加到基类中即可。
如果你的大部分代码与显示代码无关,而这些类确实与显示机制无关——每个派生类可能都应该继承自两个接口(纯抽象类)
Base
类IDisplayable
(按您的意愿命名)
并且您显示的显示方法应该接收vector<IDisplayable*>
而不是vector<Base*>
。
注意
如果您被迫使用vector<Base*>
,则应该迭代元素并将其强制转换为IDisplayable*
(static_cast
或dynamic_cast
,这实际上取决于您的情况)
这与您当前的解决方案不同,因为您只需要一个类型转换(而不是每个派生类都有一个类型)
注2
我不太喜欢重载'<lt;'和">>"运算符。我会考虑在界面中使用一个名为"display"的纯虚拟函数,而不是虚拟运算符。