【问题标题】:How to forbid C++ derived class to derive from base, but allow from another derived class如何禁止 C++ 派生类从基类派生,但允许从另一个派生类派生
【发布时间】:2016-05-29 12:05:09
【问题描述】:

鉴于这种情况:

class GrandParent {};
class Parent : public GrandParent {};
class Child : public Parent {}; /// Ok
class Child : public GrandParent {}; /// Is it possible to force a compilation error? 

【问题讨论】:

  • 如果它的唯一目的是作为Parent 的基类,为什么GrandParent 存在?
  • @PeteBecker 对于“正常”继承可能没有理由,但对于技巧,当然(base-from-member idiom,EBO,common members for main class and its specialization ...这个列表可以继续, 和上)。对于现实生活中的示例,请考虑 libstdc++ 的 std::vector
  • @milleniumbug - 此继承层次结构中没有任何内容表明它是用于“技巧”的。如果是,问题应该这样说,以便得到更合适的答案。
  • @PeteBecker,正如 milleniumbug 所说,它旨在制造一些技巧。这不是我想要的层次结构;这只是其中的一部分。但这对你来说是无关紧要的信息,我可以这么说,因为你是唯一一个抱怨过这个的人;没有冒犯的伙伴。还是谢谢你!

标签: c++ inheritance


【解决方案1】:

GrandParent 构造函数设为私有,将Parent 设为好友。

class GrandParent
{
   friend class Parent;
   private:
   GrandParent() {}
   // ...
};

或者,您可以通过将析构函数设为私有来权衡GrandParents 的多态破坏:

class GrandParent
{
   friend class Parent;
   private:
   virtual ~GrandParent() {}
};

// Invalid Destruction:
GrandParent* p = new Parent;
...
delete p;

【讨论】:

  • 可能是最简单的方法。 +1
  • 这里唯一的缺点是friend 是一揽子解决方案。不过我想不出更好的了……
  • 我会试一试的!非常感谢
【解决方案2】:

解决这个问题的另一种方法是使用“模板魔法”。 您应该在 Child 类声明之后添加此代码:

 #include <type_traits>

 class Child : public Parent
 {
 };

 static_assert(std::is_base_of<Parent, Child>::value, "Child must derive Parent");

如果您尝试将 Parent 类更改为 GrandParent,编译器会报错

【讨论】:

  • 是的,我同意你的看法。
  • 考虑到这一点,它可以扩展到做一些更可靠的事情。如果 OP 的方法采用 T * 的参数并通过 SFINAE 检查 T 是否源自 GrandParent,则 它们 可以包含 static_assertT 源自 Parent拒绝任何不是来自Parent 的东西。但这只是让我思考:OP试图完成什么?在这种情况下,更简单、更明智的方法是首先将其限制为Parent,而不用担心其他GrandParent 派生类。
  • 我不明白你的想法。
  • 我的意思是,如果 OP 有一个 Child2 *,其中 Child2 直接派生自 GrandParent,并且 OP 将 Child2 * 传递给模板函数(可能与 @ 一样简单的签名987654335@) 仅适用于Parent-派生类,可以将检查放在那里。如果该函数被广泛使用,那么您就不需要对所有子类重复检查。但同样——在那种情况下,我认为 OP 的设计可能有问题。
  • @DarioOO 我对这个答案发表了评论,因为我认为static_assert 是其中最重要的部分,那是@АлександрЛысенко 的,所以我可以将它放入这个答案中。 :)
猜你喜欢
  • 1970-01-01
  • 2012-03-05
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
  • 2016-12-12
相关资源
最近更新 更多