流运算符和多态基类列表
Streaming Operator and Polymorphic Base Class Lists
我有一个类向量,我想在屏幕上显示它们各自的参数。每个类都继承自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"的纯虚拟函数,而不是虚拟运算符。
- 为什么我需要在成员发起器列表中重复基类的模板参数?
- 在初始化列表之外手动调用基类的构造函数
- 虚拟基类的派生类列表
- 为什么 C++ 的创建者决定使用构造函数初始值设定项列表来初始化基类?
- 子类对象列表重新解释为基类对象列表?(C++11).
- 将initalizer列表与从空基类继承的结构一起使用
- 使用不包括基类的模板从C++中的列表中查找特定类型
- 流运算符和多态基类列表
- 为什么在派生最多的类的初始值设定项列表中显式调用虚拟基类构造函数的规则,而较老的祖先已经拥有它?
- 从其基类列表中调用重写的函数
- 是否可以在基类初始化器列表中传递成员对象
- 初始值设定项列表:基类和成员函数中的构造函数
- 自动将派生类的指针列表转换为基类的指针列表
- 如何制作一个既可以包含基类又可以包含派生类的列表
- 在模板基类列表中使用类本地类型别名
- 当后代需要不同的参数列表时,我应该如何在基类中定义抽象方法
- C++基类列表以及如何确定类类型
- Boost.Python:来自 python 中C++对象:无法添加到基类列表中C++
- 用于可变模板的基类列表
- 类设计以避免需要基类列表