【问题标题】:Interface Design and Inheritance in C++C++中的接口设计和继承
【发布时间】:2015-10-29 23:54:22
【问题描述】:

我需要使用 C++ 接口类在 C++ 中实现非托管 DLL。假设我有这个类结构:

class IA
{
public:

    virtual void Foo() = 0;
    ...
};

class A : public IA
{
public:

    virtual void Foo() override { ... }
    ...
};

class IB
{
public:

    virtual void Bar() = 0;
    ...
};

class B : public IB
    , public A
{
public:

    virtual void Bar() { ... }
    ...
};

现在,如果我有一个指向接口 IB 的指针,这将无法编译:

IB* b = ...;
b->Foo();

为了让它工作,我必须让IB继承自IA,这样:

class IB : public IA
{
    ...
};

但这也不会编译,因为现在B 不再是一个具体的类,编译器希望它实现IA::Foo,即使它继承自A

您可以使用虚拟继承解决此问题:

class A : public virtual IA { ... };
class IB : public virtual IA { ... };
class B : public virtual IB, public A { ... };

在 VC++ 中生成一个新警告:

warning C4250: 'B' : inherits 'A::A::Foo' via dominance

据我了解,这是因为现在有不止一个 Foo 声明。

如何在没有这些问题的情况下正确继承接口及其具体实现?

【问题讨论】:

  • @DieterLücking 这是错误的。感谢您发现它。我修好了它。 :)
  • Here is an answer that explains C4250。如果您对这种并发症没问题,那么它应该可以正常工作。
  • @Guvante 鉴于我使用虚拟继承来继承接口这一事实,我认为我不会遇到那种复杂情况。所以你会说禁用警告是安全的吗?

标签: c++ oop inheritance interface


【解决方案1】:

正如你所写,这不会编译:

IB* b = ...;
b->Foo();

当然这不会编译,因为IB 没有Foo 成员。要访问Foo,您需要一个指向IA 的指针,但IB* 不能转换为IA*

但是有一点,您可以将指针指向IB。到那时(或沿袭的某个地方),某些接口需要知道真正的B 对象,它也可以转换为IA,而不仅仅是IB。届时,您可以请求IA*,并直接使用它。

拥有IB* 的人可能甚至不知道IB 的实现是否也是IA


另一种可能性是在IB 上定义一个转换成员,它将您的指针转换为IA*。像这样:

IA * GetAsIA() = 0;

IAIB 实现也可以返回有效指针,其他实现可能返回 nullptr。

【讨论】:

  • 虽然我认为这是最安全的方法,但我认为这种解决方案不能很好地适应相对较大的项目。我认为忽略警告并执行正确的界面模式是我的情况的更好选择。
【解决方案2】:

只要IB 不尝试在除A 之外的任何地方实现IA 并且您了解B 具有依赖于A 的实现的IB 的实现(因为@987654327 @ 对IA 的实现由A 实现)您可以放心地忽略该警告。

警告的主要原因是通常您只需要向上或向下查找继承层次结构即可找到所有实现,但在这种情况下您需要横向查看,从IBA

【讨论】:

    【解决方案3】:

    在您的编译器设置中禁止 C4250 并忘记它。

    我不知道通过支配继承有任何问题。我使用的其他编译器即使在最高警告级别也从不警告它。谷歌搜索c++ inheritance dominance problem 只会引起对 C4250 的抱怨,而不是对实际代码的任何实际问题的描述。我的结论是这不是问题。

    【讨论】:

      【解决方案4】:

      如果你想消除警告,在你的编译器中抑制 C4250 的答案是一个选项。

      但是,我认为你的设计很糟糕。

      • 您的“B”类依赖于具体类(“A”类)。
      • 您正在使用多重继承。这很少是一个很好的解决方案。

      我认为您应该尝试建立Has-a 的关系而不是Is-a

      class IA
      {
      public:
          virtual void Foo() = 0;
          ...
      };
      
      class A : public IA
      {
      public:
          virtual void Foo() override { ... }
          ...
      };
      
      class IB
      {
      public:
          virtual void Bar() = 0;
          ...
      };
      
      class B : public IB
      {
      private:
          IA* ptrIA;
      public:
          B(IA* ia): ptrIA(ia) {}
      
          virtual void Bar() { ... }
          void performeFoo() { ptrIA->Foo(); }
          ...
      };
      

      【讨论】:

        猜你喜欢
        • 2019-09-29
        • 1970-01-01
        • 2010-09-15
        • 1970-01-01
        • 2011-07-31
        • 1970-01-01
        • 2021-08-10
        • 1970-01-01
        • 2011-04-22
        相关资源
        最近更新 更多