假设我有一个接口IControllable
,3个类继承了该接口:MachineControllable, LightControllable, OtherControllable
,它有一些特定的数据和方法。
现在我确实只想拥有一个所有IControllable
的容器,所以我创建了一个矢量容器。
vector<IControllable> allControllables; // and put all the MachineControllable,
//LightControllable, OtherControllable here by the IControllable interface class.
但现在的问题是,我只能使用IControllable
定义的内容,而不是特定Controllable的具体数据和方法。
我应该为每个Controlable分配容器,还是我的逻辑在OOP方面是错误的?
答案 0 :(得分:4)
“我应该为每个Controlable分配容器,还是我的逻辑在OOP方面是错误的?”
不,你的逻辑没问题。问题是,你不能实例化一个抽象类。
你应该有一个容器保持指向IControllable
接口的指针,例如:
vector<IControllable*> allControllables;
或
vector<std::unique_ptr<IControllable>> allControllables;
或
vector<std::shared_ptr<IControllable>> allControllables;
答案 1 :(得分:2)
如上所述,你的向量应该包含某种指针,而不是基础对象本身。
一旦有了这个,你需要一种方法来获取容器中实际对象类型的特定指针。标准方法是使用dynamic_cast
:
IMachineControllable * p = dynamic_cast<IMachineControllable*>(allControllables[i]);
如果选择了错误的类型,则会得到一个NULL指针。
如果这些是Microsoft COM接口,则需要使用替代方法,但除非您说明您的所有内容,否则我不会参与其中。
答案 2 :(得分:1)
这可能不是唯一的问题。容器需要价值 语义,并包含您放入的对象的副本 他们。继承通常不适用于copy和 任务:想想如果你有什么可能意味着什么:
*p = *q;
其中p
和q
为IControllable*
,但p
指向
MachineControllabe
,但是q
到LightControllable
。作为一个
一般规则(并且是例外),你应该做
接口不可操作且不可分配。通常,他们也是
还将包含纯虚函数,这意味着你
无法实例化它们。在任一情况下,
std::vector<IControllable>
甚至不会编译。
您可能想要的是std::vector<IControllable*>
。
无论如何,多态性只能通过指针或引用来工作
(你不能有参考文献)。
答案 3 :(得分:1)
但现在的问题是,我只能使用IControllable 定义,而不是特定Controllable的具体数据和方法。
我应该为每个可控制器分配容器,还是我的 逻辑在OOP方面是错误的吗?
这取决于您对对象的要求。
如果您需要通过IControllable
界面使用 heavy 使用所有IControllable
个对象,那么将它们全部放在一个容器中是有意义的。
另一方面,如果您想重使用特定的接口,那么拥有单独的容器也是有道理的。
如果你需要同时做到这两点,那么两者都没有错。
现在,如果您选择将所有内容放在一个容器中,那么您必须使用某种指针/智能指针,因为按值存储不同类型将导致切片并且不允许多态> em>执行。
但是,如果可能,最好通过 value 将对象存储在容器中。因此,如果您使用多个容器,则按存储将更为可取。
如果要同时执行这两项操作,则可以按值将对象存储在单独的容器中,并将其指针存储在catch-all容器中。在这种情况下,按值存储的容器将拥有对象,因此catch-all容器应不拥有它们 - 使用原始指针:
struct IControllable { virtual ~IControllable() {} };
struct MachineControllable: IControllable {};
struct LightControllable: IControllable {};
struct OtherControllable: IControlable {};
// store by value if possible (not always possible)
std::vector<MachineControllable> machingControlables;
std::vector<LightControllable> lightControlables;
std::vector<OtherControlable> otherControlables;
std::vector<IControlable*> allControlables; // raw pointers (non owned)
如果您不想单独存储对象,那么您的catch-all容器需要拥有对象:
// these objects die when this container dies.
std::vector<std::unique_ptr<IControlable>> allControlables;
所以真正的问题是你如何将大部分时间花在处理这些特定类型和/或一般(基础)类型上?
您还想要数据结构的复杂程度吗?如果使用多个容器,则会增加管理数据的复杂性。
请注意,如果您不为特定的类型使用单独的容器,则必须将它们转换为特定的调用:
for(auto& controlable: allControlables)
{
MachineControllable* mc;
LightControllable* lc;
OtherControllable* oc;
if((mc = dynamic_cast<MachineControllable*>(controlable.get())))
mc->machine_specific();
else if((lc = dynamic_cast<LightControllable*>(controlable.get())))
lc->light_specific();
else if((oc = dynamic_cast<OtherControllable*>(controlable.get())))
oc->other_specific();
}
不理想。