代码之家  ›  专栏  ›  技术社区  › 

C++用法/技巧中的虚拟继承

  •  2
  •  · 技术社区  · 6 年前

    我从未在专业软件中使用过它,即使在我们的商店和我工作过的其他地方,我们设计了大型系统。我唯一一次搞虚拟继承是在一家公司面试时。尽管如此,我还是在下午玩它。

    你们用它吗?您是否深入了解它的工作原理(大多数流行的编译器供应商是如何实现它的)?我真的很想知道它是如何在专业软件中使用的,如果有的话。技巧和窍门也将被欣赏。

    对我来说,虚拟继承只是一个臭名昭著的钻石问题的解决方案。因此,它从未在我们的软件中找到它的方式,因为我们的架构中没有导致钻石的MI。

    谢谢

    6 回复  |  直到 16 年前
        1
  •  6
  •   Charlie Martin    16 年前

    虚拟继承的要点是防止派生类继承不同上级类的多个副本。这可能发生在任何可能存在多重继承的情况下——正如您正确地注意到的,“菱形问题”,也就是说继承图是DAG而不是严格的树。

    这个 C++ FAQ goes into it in some detail

        2
  •  5
  •   dirkgently    16 年前

    我从未在专业软件中使用过它,即使在我们店里,

    你用什么 iostream ? 是的。查阅iostreams的设计,你就会知道你一直在使用虚拟继承。

        3
  •  4
  •   Sebastian Mach    7 年前

    http://www.research.att.com/~bs/bs_faq2.html#no-derivation 有关更新的超链接和来源,请参见下文):

    [...]
    

    对于较旧的编译器,可以使用有点笨拙的技术: 类可用;

      class Usable_lock {
          friend class Usable;
      private:
          Usable_lock() {}
          Usable_lock(const Usable_lock&) {}
      };
    
    class Usable : public virtual Usable_lock {
        // ...
    public:
        Usable();
        Usable(char*);
        // ...
    };
    
    Usable a;
    class DD : public Usable { };
    
    DD dd;  // error: DD::DD() cannot access
            // Usable_lock::Usable_lock(): private  member
    

    C++已经收到了 final in the meanwhile :

    为什么C++没有最终的关键字?

    It has, but it is not as useful as you might think.

    这导致:

    是的,但你为什么要这么做?有两个常见的答案:

    • 为了提高效率:避免我的函数调用是虚拟的
    • 出于安全考虑:确保我的类不被用作基类(例如,

    根据我的经验,效率的原因通常是错位的恐惧。在C++中,虚拟函数调用速度太快,它们与虚拟函数一起设计的类的实际使用不会产生与使用普通函数调用的替代方案相比可测量的运行时开销。请注意,虚拟函数调用机制通常仅在通过指针或引用调用时使用。当直接为命名对象调用函数时,虚拟函数类开销很容易优化。

    如果真的需要“封顶”类层次结构以避免虚拟函数调用,人们可能会问为什么这些函数首先是虚拟的。我见过一些例子,其中性能关键型功能被虚拟化是没有充分理由的,只是因为“这是我们通常的做法”。

    这个问题的另一个变体,如何防止逻辑原因的派生,在C++11中有一个解决方案。例如:

      struct Base {
          virtual void f();
      };
    
      struct Derived final : Base {   // now Derived is final; you cannot derive from it
          void f() override;
      };
    
      struct DD: Derived {// error: Derived is final
    
          // ...
      };
    

    ... 这就引出了这个答案的第一段。

        4
  •  2
  •   LegendLength    16 年前

    如果你碰巧使用了MI,我不明白你为什么这么做 不会

        5
  •  0
  •   anon anon    16 年前

        6
  •  0
  •   rmn    16 年前

    要进一步了解虚拟继承,您还可以查看以下帖子: http://cpptalk.wordpress.com/2009/08/11/constructor-selection-with-virtual-inheritance/ 我对这个机制有深入的了解,所以如果你有一个具体的问题,尽管问吧。