c++多重继承/虚拟继承

C++ multiple inheritance / virtual inheritance

本文关键字:继承 虚拟 多重继承 c++      更新时间:2023-10-16

对于一个项目,我想对库接口隐藏一些实现细节。我想到的处理这种"高效"(在编码和维护方面)的唯一方法是基于相同抽象基的抽象和具体基类的多重继承。所以,是的,我最终得到了一个扩展的钻石结构。

我通常尽可能避免多重继承,因为它很复杂,所以我在使用它方面不是很有经验,所以我不确定我提出的设计是否有一些我没有注意到的缺陷。

基本上我需要提供多个"工具"。这些"工具"当然有一些实现细节,我想用接口abc隐藏,例如:

类Tool1Impl: public ITool1;

类Tool2Impl: public ITool2;

然而,当然这些工具有相当多的共性。

所以我希望有一个共同的基类,但实现细节应该通过接口隐藏。

我想出了以下(菱形)方案:

            ITool                                           
          /   |                  
        /     |     
      /       |       
ITool1  ToolImplBase   ITool2  ... IToolN
         /            /
        /            /
       /            /
   ToolImpl1      ToolImpl2    ... IToolImplN

ToolImplBase实现ITool的纯虚拟功能。ToolImpl1实现了ITool1中声明的纯虚拟功能。

实现大纲如下:

class ITool {
public:
  virtual int common_foo(int a) = 0;
};
class ITool1 : public virtual ITool {
public:
  virtual int specific_foo(int b) = 0;
};
class ITool2 : public virtual ITool {
public:
  virtual int specific_bar(int c) = 0;
};
class ToolImplBase : public virtual ITool {
public:
  virtual int common_foo(int a) override;
protected:
  int _some_common_data;
};
class ToolImpl1 : public ToolImplBase, public virtual ITool1 {
public:
  virtual int specific_foo(int b) override;
private:
  int _some_specific_data;
};
class ToolImpl2 : public ToolImplBase, public virtual ITool2 {
public:
  virtual int specific_bar(int c) override;
private:
  int _some_specific_data;
};

它似乎做了我想要的,但我不确定是否有任何潜在的陷阱或明显的问题。我也不确定继承方案中的"虚拟"是否正确(不是虚拟方法,而是":public virtual")。一个问题是,MSVC(我被困在2010年由于一些外部依赖在这个时候)给了我一个编译器警告C4250:

warning C4250: 'ToolImpl1': inherits'ToolImplBase::ToolImplBase::common_foo' via dominance

我可以忽略它吗?我甚至不确定为什么我得到这个,因为"common_foo"的非主导方式是纯虚拟的,所以实际上没有有效的"非主导"实现。

感谢您的任何输入(除了"永远不要使用M.I.",我已经尽量避免它了)。

这里有一些关于警告的解释:c4250vc++警告是什么意思?

我认为你的代码没有问题,因为你把ITool1设计成一个接口。

如果您在ITool1中实现common_foo函数,那么当您创建ToolImpl1时,您将不知道common_foo的哪个实现将工作。

你会小心这个问题,但是任何人都可以在IToolX实现中合法地实现common_foo功能而不会引发错误。

我最后的评论是:为什么你需要你的ITool1ITool派生出来?ToolImpl1已经从ToolImplBase派生,所以你的实际实现类将始终从ITool派生。

我将更改IToolX接口如下

class IToolX{
    public:
    virtual int specific_foo(int b) = 0;
};