Pergunta

Nós temos uma restrição que uma classe não pode agir como uma base de classe para mais de 7 classes. Existe uma maneira de fazer cumprir a regra acima em tempo de compilação?

Estou ciente da técnica Usable_Lock de Andrew Koenig para evitar uma classe de ser herdada mas falharia somente quando tentamos instanciar a classe. Pode isso não ser feito ao derivar em si?

A base de classe é permitido saber quem são seus filhos. Então eu acho que nós podemos declarar uma combinação de amigo classes e encapsular-los para fazer cumprir esta regra. Suponha que nós tentar algo como isto

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

class BB : public AA {

};

class CC : public AA 
{};

A derivação de classe CC geraria um aviso do compilador abt dtor inacessível. Podemos, então, bandeira tais avisos como erros usando ajustes do compilador (como bandeira de todos os avisos como erros), mas eu não gostaria de contar com tais técnicas.

Outra maneira, mas para mim parece um pouco desajeitado é: -

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{};

A derivação de classe D será sinalizado como um erro do compilador, ou seja, todas as classes a serem derivados deverão ser derivado dentro da classe B. Isso permitirá que pelo menos uma inspeção do número de classes derivadas da classe A, mas não iria impedir que alguém de adicionar mais.

alguém aqui que tem uma maneira de fazê-lo? Melhor ainda se a necessidade da classe base não saber quem são seus filhos.

NOTA:. A classe que age como uma classe de base em si pode ser instanciado (não é abstrato)

Agradecemos antecipadamente,

Editar 1: Como por comentário de jon.h, uma ligeira modificação

// 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;
}
Foi útil?

Solução

Estou cansado como porcaria, mal consegue manter os olhos abertos, então não há provavelmente uma maneira mais elegante de fazer isso, e eu certamente não estou endossando a idéia bizarra de que a base deve ter no máximo sete subclasses.

// 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;
}

Comentário de jon.h:

Como é que esta paragem por exemplo: class Fail: Base de dados de público {}; ? \

Não faz. Mas, então, nem se exemplo original do OP.

Para o OP: a sua revisão da minha resposta é praticamente uma aplicação direta de Coplien de "template recorrentes Curiosamente padrão "]

Eu tinha considerado que, como bem, mas o problema com que não há nenhuma relação de herança entre uma derived1 : pubic base<derived1> e uma derived2 : pubic base<derived2>, porque base<derived1> e base<derived2> duas classes completamente alheios.

Se a sua única preocupação é herança de implementação, isso não é problema, mas se você quiser herança da interface, as pausas de soluções que.

Eu acho que há uma maneira de obter tanto herança e uma sintaxe mais limpa; como mencionei eu estava muito cansado quando eu escrevi a minha solução. Se nada mais, fazendo Realbase uma classe base da Base de Dados no seu exemplo é uma solução rápida.

Há provavelmente um número de maneiras de limpar isso. Mas eu quero enfatizar que eu concordo com markh44: mesmo que a minha solução é mais limpo, ainda estamos bagunçando o código em apoio de uma regra que não faz muito sentido. Só porque isso pode ser feito, não significa que ele deve ser.

Se a classe base em questão é de dez anos de idade e frágil demais para ser herdada de, a verdadeira resposta é para corrigi-lo.

Outras dicas

Desculpe, eu não sei como impor qualquer limite usando o compilador.

Pessoalmente eu não iria incomodar a tentar forçar a regra para o código em si - você está bagunçando o código com coisas que não tem nada a ver com o que o código está fazendo -. Não é um código limpo

Em vez de saltar através de aros, eu tentar obter essa regra relaxou. Em vez disso, deve ser uma diretriz que poderia ser quebrado se necessário e de acordo com os outros na equipe.

É claro que não têm o conhecimento de exatamente o que você está fazendo de modo que a regra poderia ser apropriada, mas em geral ele provavelmente não é.

Qualquer programação "regra" que diz que você nunca deve fazer x ou você deve sempre fazer y é quase sempre errado! Observe a palavra "quase" lá dentro.

Às vezes você pode necessidade aulas mais de 7 derivados - o que você faz então? Saltar através de aros mais. Além disso, por 7? Por que não 6 ou 8? É tão arbitrária -. Um outro sinal de uma regra pobre

Se você deve fazê-lo, como diz JP, análise estática é provavelmente o melhor caminho.

Muitas das várias ferramentas de análise estática de código fornecer informações sobre hierarquia de herança. Ao invés de tentativa e manipulá-lo em seu código, gostaria de olhar para uma ferramenta que poderia configurar algumas regras para a hierarquia de herança e falhar a compilação que essas regras não forem seguidas. Pode custar um pouco de $ e você pode ter que escrever uma regra personalizada (eu vi profundidade herança, mas não herança "amplitude" como você quiser). Mas, no longo prazo, eu acho que é a sua melhor aposta.

Per comentário: Eu usei Coverity com algum sucesso. spendy pouco. Há SO tópicos que podem ter melhores opções.

Ao invés de poluir o código com afirmações, você pode ser capaz de usar algo como GCC-XML , que analisa origem C ++ usando a saída XML g ++ compilador interface e gera. Espero que seria razoavelmente simples para desenvolver uma ferramenta que analisa esta saída e verifica se há violações da regra; este poderia então ser integrado com o código-fonte do check-in.

BTW, tendo classes base sabe sobre seus descendentes viola a Princípio Open-Closed , o que significa que ele realmente enfraquece a utilidade de programação OO em geral. O razão principal para separar código em classes base e subclasses é para que a classe base não tem que saber sobre suas subclasses - o que torna possíveis coisas como plug-in pacotes entregues após instalação.

scroll top