【问题标题】:C++ inheritance, interfacesC++ 继承、接口
【发布时间】:2015-06-07 16:26:37
【问题描述】:

假设我有一个接口IControllable,3 个类继承了该接口:MachineControllable, LightControllable, OtherControllable,其中有一些特定的数据和方法。

现在我只想拥有所有IControllable 中的一个容器,所以我创建了一个矢量容器。

vector<IControllable> allControllables; // and put all the MachineControllable,
//LightControllable, OtherControllable here by the IControllable interface class.

但是现在的问题是,我只能使用IControllable定义的东西,而不是具体可控的具体数据和方法。

我是否应该为每个 Controllable 使用单独的容器,或者我的逻辑在 OOP 方面有什么错误?

【问题讨论】:

    标签: c++ inheritance interface


    【解决方案1】:

    “我是否应该为每个 Controllable 设置单独的容器,或者我的逻辑在 OOP 方面有什么错误?”

    不,你的逻辑没问题。问题是,你不能实例化一个抽象类。

    您应该有一个容器来保存指向IControllable 接口的指针,例如:

     vector<IControllable*> allControllables;
    

     vector<std::unique_ptr<IControllable>> allControllables;
    

     vector<std::shared_ptr<IControllable>> allControllables;
    

    【讨论】:

    • 可能不是unique_ptr;一个容器应该拥有这样的对象是非常罕见的。可能是shared_ptr,但大多数时候,原始指针是最合适的。
    • 是的,对 unique_ptr 也有同样的想法,但答案一扫而光,谢谢。
    • 另外一点:他的代码编译的事实让我认为他的IControllable 不是抽象的(这可能是他的设计错误——接口类通常应该是抽象的)。
    • @JamesKanze 我没有看到任何证据,OP 说,代码可以编译。
    • 很难确定,因为英语显然不是OP的母语,但是像“我只能使用IControllable定义的东西”这样的陈述似乎表明他可以使用一些东西;即代码编译。
    【解决方案2】:

    如前所述,您的向量应该包含某种类型的指针,而不是基础对象本身。

    一旦你有了它,你需要一种方法来获取指向容器中实际对象类型的特定指针。标准方式是dynamic_cast:

    IMachineControllable * p = dynamic_cast<IMachineControllable*>(allControllables[i]);
    

    如果你选择了错误的类型,你会得到一个 NULL 指针。

    如果这些是 Microsoft COM 接口,则需要使用另一种方法,但除非你声明这是你所拥有的,否则我不会深入讨论。

    【讨论】:

    • 正在考虑这个问题,并且对演员表有相同的想法,谢谢你的例子。我对 c++/oop 的知识已经很模糊了,只是有时很难把它们放在一起^^
    • 我会非常怀疑需要dynamic_cast 才能工作的界面。有些情况是合适的,但很少见。他应该可以通过界面中的虚函数来使用对象。
    • 你能举个例子“他应该能够通过界面中的虚函数使用对象”@JamesKanze 吗?
    【解决方案3】:

    这可能不是唯一的问题。容器需要价值 语义,并包含您放入的对象的副本 他们。继承通常不适用于复制和 作业:想想如果你有这可能意味着什么:

    *p = *q;
    

    其中pqIControllable*,但p 指向一个 MachineControllabe,但 qLightControllable。作为一个 一般规则(个例外),你应该制定 接口不可复制和不可分配。此外,通常,他们 还将包含纯虚函数,这意味着您 无法实例化它们。在任一情况下, std::vector&lt;IControllable&gt; 甚至无法编译。

    您可能想要的是std::vector&lt;IControllable*&gt;。 无论如何,多态性只能通过指针或引用起作用 (而且你不能有引用向量)。

    【讨论】:

    • 你能举个例子“他应该能够通过界面中的虚函数使用对象”@James Kanze 吗?
    • @Tomas 你知道什么是虚函数吗?或者什么是纯虚函数:接口通常包含纯虚函数。 (否则,它不是接口。)通常,在多态层次结构中,所有行为都应该可以通过接口中的纯虚函数获得。 (派生类扩展接口或实现多个接口时会有例外。但您应该从简单开始,情况并非如此。)
    【解决方案4】:

    但是现在的问题是,我只能使用 IControllable 什么的 定义,而不是具体Controllable的具体数据和方法。

    我是否应该为每个 Controllable 使用单独的容器,或者我的 在 OOP 方面逻辑是错误的?

    这取决于你想对你的对象做什么。

    如果您需要通过IControllable 接口大量使用所有IControllable 对象,那么将它们全部放在一个容器中是有意义的。

    另一方面,如果您希望大量使用它们的特定接口,那么使用单独的容器也是有意义的。

    如果你需要两者都做,那么两者都做没有错。

    现在,如果您选择将所有内容放在一个容器中,那么您必须使用某种指针/智能指针,因为存储不同类型按值会导致切片并且不允许多态 em> 执行。

    但是,如果可能的话,最好按将对象存储在容器中。因此,如果您使用 多个 容器存储 按值 会更好。

    如果你想两者都做,那么你可以将对象按值存储在单独的容器中,并将它们的指针存储在一个包罗万象的容器中。在这种情况下,按值存储的容器将拥有对象,因此包罗万象的容器应该拥有它们 - 为此使用原始指针:

    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)
    

    如果您不想单独存储对象,那么您的包罗万象的容器需要拥有这些对象:

    // 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();
    }
    

    不理想。

    【讨论】:

      猜你喜欢
      • 2011-03-24
      • 2023-03-14
      • 2017-07-23
      • 2011-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-11
      相关资源
      最近更新 更多