如何禁止C++派生类从基类继承,但允许从另一个派生类继承?

19

考虑到这种情况:

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

4
如果它只是作为Parent的基类存在,那么为什么需要GrandParent呢? - Pete Becker
1
@PeteBecker 对于“普通”的继承来说可能没有理由,但对于一些技巧来说,当然是有的(如基于成员的继承惯用法、EBO、主类和其特化类的共同成员等等,这个列表可以不断延伸)。以实际例子为例,考虑libstdc++的std::vector - milleniumbug
@milleniumbug - 这个继承层次结构中没有任何暗示它是用于“技巧”的。如果是的话,问题应该明确说明,以便获得更合适的答案。 - Pete Becker
@PeteBecker,正如milleniumbug所说,它旨在制造一些技巧。这不是我想要的层次结构;它只是其中的一部分。但这对你来说是无关紧要的信息,我可以这么说,因为你是唯一一个抱怨这个问题的人;没有冒犯的意思啊。无论如何,还是谢谢你! - pacorrop
2个回答

39

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 - Marco A.
这里唯一的缺点是 friend 是一个笼统的解决方案。不过我想不出更好的办法了... - rubenvb
我会尝试的!非常感谢。 - pacorrop

0
另一种解决此问题的方法是使用“模板魔法”。 您应该在子类声明后添加此代码:
 #include <type_traits>

 class Child : public Parent
 {
 };

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

如果你试图将父类更改为祖父类,编译器会报错。


是的,我同意你的观点。 - Alex Aparin
思考一下,它可以扩展以更可靠地执行某些操作。如果 OP 具有具有 T * 参数的方法,并带有 SFINAE 检查,以检查 T 是否派生自 GrandParent他们 可以包含一个 static_assert,以拒绝任何未从 Parent 派生出来的内容。但这让我想:OP试图实现什么?在那种情况下,更简单和更明智的方法是首先将其限制为Parent,而不必担心其他源于GrandParent的类。 - user743382
我不太理解你的想法。 - Alex Aparin
我的意思是,如果OP有一个Child2 *,其中Child2直接派生自GrandParent,并且OP将该Child2 *传递给一个模板函数(可能只是一个签名简单的template <typename T> void f(T *)),该函数旨在仅与派生自Parent的类一起使用,那么可以在其中放置检查。如果该函数被广泛使用,那么您就不需要为所有子类重复检查。但是再说一遍 - 在这种情况下,我认为OP的设计可能存在问题。 - user743382
1
@DarioOO 我评论了这个回答,因为我认为static_assert是其中最重要的部分,并且那是 @АлександрЛысенко的,所以如果它被放在这个答案中,我也没问题。 :) - user743382
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接