2009-04-30 48 views
3

我们有一个限制,即一个类不能作为超过7个类的基类。 有没有办法在编译时强制执行上述规则?在编译时将继承限制为期望数量的类

我知道Andrew Koenig的Usable_Lock技术可以防止类被继承,但只有当我们尝试实例化类时它才会失败。这不能在派生自己的时候完成吗?

允许基类知道谁是它的子女。所以我想我们可以声明一个朋友 类的组合并封装它们来执行这个规则。假设我们尝试这样的事情

class AA { 
    friend class BB; 
    private: 
     AA() {} 
     ~AA() {} 
}; 

class BB : public AA { 

}; 

class CC : public AA 
{}; 

CC类的派生会生成一个编译器警告abt无法访问的dtor。然后,我们可以使用编译器调整(例如将所有警告标记为错误)来标记 等警告,但我不想依赖这种技术。

的另一种方式,但对我来说看起来相当笨拙是: -

class B; 

class InheritanceRule{ 
    class A { 
    public: 
     A() {} 
     ~A() {} 
    }; 
    friend class B; 
}; 

class B { 
public: 
    class C : public InheritanceRule::A 
    {}; 
}; 


class D : public InheritanceRule::A{}; 

d类的派生将被标记为编译器错误,意思是派生类应该B.内部派生的所有类这将允许至少检查从A类派生的类的数量,但不会阻止任何人增加更多。

这里有谁有办法吗?如果基地级别不需要知道谁是其子女,那更好。

注意:充当基类的类本身可以被实例化(它不是抽象的)。

由于提前,

EDIT-1:按照从jon.h注释,稍微修改

// create a template class without a body, so all uses of it fail 
template < typename D> 
class AllowedInheritance; 

class Derived; // forward declaration 
// but allow Derived by explicit specialization 
template<> 
class AllowedInheritance< Derived> {}; 

template<class T> 
class Base : private AllowedInheritance<T> {}; 

// privately inherit Derived from that explicit specialization  
class Derived : public Base<Derived> {}; 

// Do the same with class Fail Error 
// it has no explicit specialization, so it causes a compiler error 
class Fail : public Base<Fail> {}; // this is error 

int main() 
{ 
    Derived d; 

    return 0; 
} 
+4

为什么选择7? – Shog9 2009-04-30 05:22:03

+0

>注意:充当基类的类本身可以被实例化(它不是抽象的)。 等等,认真吗?你有一个关于子类的数量的任意规则,这没有任何可以想象的目的,但不是关于使抽象的基础,这是什么? – tpdi 2009-04-30 05:38:49

+0

@ Shog9:我不知道为什么它只有7,它可能是我认为的任何数字。项目建筑师不喜欢nos> 7我猜:-) @tpdi:候选基类可能并不总是一个iterface。 老实说,我也不明白这背后的概念,除了放牧不驯的遗传承认程序员,但我会在稍后处理。目前我正在尝试查看是否有任何解决方案。 – Abhay 2009-04-30 05:43:28

回答

2

我累了的废话,只能勉强眼睛都睁不开,所以有可能是一个更优雅的方式来做到这一点,我当然不会赞同这一古怪的想法,一个基地应该有至多七个子类。从jon.h

// create a template class without a body, so all uses of it fail 
template < typename D, typename B> class AllowedInheritance; 


class Base {}; 
class Derived; // forward declaration 

// but allow Derived, Base by explicit specialization 

template<> class AllowedInheritance< Derived, Base> {}; 

// privately inherit Derived from that explicit specialization  
class Derived : public Base, private AllowedInheritance<Derived, Base> {}; 


// Do the same with class Compiler Error 
// it has no explicit specialization, so it causes a compiler error 
class CompileError: public Base, 
    private AllowedInheritance<CompileError, Base> { }; 

//error: invalid use of incomplete type 
//‘struct AllowedInheritance<CompileError, Base>’ 


int main() { 

    Base b; 
    Derived d; 
    return 0; 
} 

评论:

这是如何停止例如:类故障:公共基础{}; ? \

它没有。但是,OP的最初例子也没有。

To the OP: your revision of my answer is pretty much a straight application of Coplien's "Curiously recurring template pattern"]

我会考虑为好,但与这个问题有一个derived1 : pubic base<derived1>derived2 : pubic base<derived2>之间没有继承关系,因为base<derived1>base<derived2>是两个完全不相关的类。

如果你唯一关心的是继承的实现,这是没有问题的,但是如果你想继承接口,你的解决方案会打破这个。

我认为有一种方法可以同时获得继承和更干净的语法;正如我所提到的,当我编写解决方案时,我感到非常疲倦如果没有别的,通过在您的示例中将RealBase作为基类的基类是一个快速修复。

可能有很多方法可以清除它。但我想强调的是,我同意markh44:即使我的解决方案更清晰,我们仍然混淆了代码以支持一条毫无意义的规则。只是因为这可以做到,并不意味着它应该。

如果有问题的基类是十岁,太脆弱而无法继承,真正的答案是解决它。

+0

+1,绝对更清洁。虽然我将不得不与这个规则的架构师一起检查是否允许使用模板:-) – Abhay 2009-04-30 06:30:47

2

大量的各种静态代码分析工具提供有关继承层次结构信息。与其试图在代码中处理它,我会研究一个可以为继承层次结构设置一些规则的工具,如果没有遵循这些规则,就会使构建失败。可能花费一点点$,你可能不得不写一个自定义规则(我已经看到了继承深度,但不像你想要的那样继承“宽度”)。但是,从长远来看,我认为这是你最好的选择。

评论:我用Coverity取得了一些成功。有点花。有several good SO threads可能有更好的选择。

+0

感谢您的建议。你可以引用那些给你一个很好的经验w.r.t静态代码分析的工具吗?我会检查一样的。 – Abhay 2009-04-30 05:50:38

4

对不起,我不知道如何使用编译器强制执行任何此类限制。

就我个人而言,我不打算试图强制规则进入代码本身 - 你在与代码正在做的事情无关的代码混乱 - 这不是干净的代码。

与其跳过箍环,我试图让规则放松。相反,它应该是一个指导方针,必要时可以打破,并与团队中的其他人达成一致。

当然,我不知道你在做什么,所以规则可能是适当的,但一般来说它可能不是。

任何编程“规则”,说你绝不能做x或者你必须总是做y几乎总是错的!在那里注意“几乎”这个词。

有时你可能需要 7个以上的派生类 - 那你做什么?跳过更多的篮球。另外,为什么是7?为什么不是6或8?这太随意了 - 这是一个糟糕的规则的另一个迹象。

如果你必须这样做,正如JP所说,静态分析可能是更好的方法。

1

您可能可以使用类似GCC-XML的东西来代替使用g ++编译器前端分析C++源代码,并生成XML输出,而不是使用断言混淆代码。我期望开发一个工具来分析这个输出并检查是否违反规则是合理的直截了当;这可以与源代码签入集成。

顺便说一句,有基类知道他们的后代违反Open-Closed Principle,这意味着它实际上削弱了一般的OO编程的用处。 主要原因用于将代码分离到基类和子类中,以便基类不必知道关于它的子类 - 这使安装后交付插件包成为可能。