Pergunta

Quais são os prós e contras do uso de classes e enumerações aninhados público C ++? Por exemplo, suponha que você tenha uma classe chamada printer, e esta classe também armazena informações sobre bandejas de saída, você poderia ter:

class printer
{
public:
    std::string name_;

    enum TYPE
    {
        TYPE_LOCAL,
        TYPE_NETWORK,
    };

    class output_tray
    {
        ...
    };
    ...
};

printer prn;
printer::TYPE type;
printer::output_tray tray;

Como alternativa:

class printer
{
public:
    std::string name_;
    ...
};

enum PRINTER_TYPE
{
    PRINTER_TYPE_LOCAL,
    PRINTER_TYPE_NETWORK,
};

class output_tray
{
    ...
};

printer prn;
PRINTER_TYPE type;
output_tray tray;

Eu posso ver os benefícios de nidificação enums / aulas particulares, mas quando se trata das públicas, o escritório está split -. Parece ser mais uma opção de estilo

Então, o que você prefere e por quê?

Foi útil?

Solução

Classes aninhadas

Existem vários efeitos colaterais para classes aninhadas dentro de classes que eu costumo considerar falhas (se não antipatterns puros).

Vamos imaginar o seguinte código:

class A
{
   public :
      class B { /* etc. */ } ;

   // etc.
} ;

Ou mesmo:

class A
{
   public :
      class B ;

   // etc.
} ;

class A::B
{
   public :

   // etc.
} ;

Assim:

  • Privilegied Acesso: A :: B tem acesso privilegied a todos os membros de uma (métodos, variáveis, símbolos, etc.), o que enfraquece o encapsulamento
  • escopo de A é candidato para pesquisa símbolo: código de dentro B vai ver todos símbolos de um como possíveis candidatos para uma pesquisa de símbolo, o que pode confundir o código
  • forward-declaração: Não há nenhuma maneira de transmitir-declare A :: B sem dar uma declaração completa de A
  • extensibilidade: É impossível adicionar outra classe A :: C a menos que você é proprietário de A
  • Code verbosidade: colocando aulas em classes só faz cabeçalhos maior. Você ainda pode separar isso em várias declarações, mas não há nenhuma maneira de uso namespace-como aliases, importações ou usings.

Como conclusão, a menos que exceções (por exemplo, a classe aninhada é uma parte íntima da classe de nidificação ... E mesmo assim ...), não vejo nenhum ponto em classes aninhadas no código normal, como as falhas outweights por magnitudes as vantagens percebidas.

Além disso, o cheiro é como uma tentativa desajeitado para simular namespacing sem o uso de espaços de nomes de C ++.

No lado profissional, você isolar esse código, e se privado, inutilizá-lo, mas a partir da classe "fora" ...

Nested enums

Prós:. Tudo

Con:. Nada

O fato é itens enum vai poluir o escopo global:

// collision
enum Value { empty = 7, undefined, defined } ;
enum Glass { empty = 42, half, full } ;

// empty is from Value or Glass?

Ony colocando cada enum em um namespace diferente / aula lhe permitirá evitar essa colisão:

namespace Value { enum type { empty = 7, undefined, defined } ; }
namespace Glass { enum type { empty = 42, half, full } ; }

// Value::type e = Value::empty ;
// Glass::type f = Glass::empty ;

Note que o C ++ 0x definiu a enumeração de classe:

enum class Value { empty, undefined, defined } ;
enum class Glass { empty, half, full } ;

// Value e = Value::empty ;
// Glass f = Glass::empty ;

exatamente para este tipo de problemas.

Outras dicas

Um con que pode se tornar um grande negócio para grandes projetos é que é impossível fazer uma declaração para a frente para classes aninhadas ou enums.

Se você nunca vai estar usando a classe dependente para qualquer coisa, mas trabalhar com implementações da classe independente, classes aninhadas são muito bem, na minha opinião.

É quando você quer estar usando a classe "interno" como um objeto em seu próprio direito que as coisas podem começar a ficar um pouco manky e você tem que começar a escrever extractor / inserção rotinas. Não uma situação bastante.

Parece que você deve estar usando namespaces em vez de aulas de grupo como coisas que estão relacionados uns aos outros desta forma. Um con que eu podia ver em fazer classes aninhadas é que você acabar com uma muito grande arquivo de origem que pode ser difícil de Grokar quando você estiver procurando por uma seção.

Não há prós e contras, por si só de usar classes aninhadas público C ++. Há apenas fatos. Esses fatos estão mandatados pelo C ++ padrão. Se um fato sobre classes aninhadas público C ++ é um profissional ou um con depende do problema específico que você está tentando resolver. O exemplo que você deu não permite um julgamento sobre se classes aninhadas são apropriados ou não.

Um fato sobre classes aninhadas é que eles têm acesso privilegiado a todos os membros da classe a que pertencem. Este é um golpe, se as classes aninhadas não precisa de tal acesso. Mas se a classe aninhada não precisa de tal acesso, então ele não deveria ter sido declarada como uma classe aninhada. Há situações, quando uma classe A quer conceder acesso privilegiado a determinadas classes B . Há três soluções para este problema

  1. Faça B um amigo de A
  2. Faça B uma classe aninhada da A
  3. Faça os métodos e atributos, que B necessidades, membros públicos de A .

Nesta situação, é # 3, que viola o encapsulamento, porque A tem o controle sobre seus amigos e sobre suas classes aninhadas, mas não sobre as classes que chamam seus métodos públicos ou de acesso Seus atributos públicos.

Outro fato sobre classes aninhadas é que é impossível adicionar outra classe A :: C como uma classe aninhada da A , a menos que você é o proprietário de A . No entanto, isso é perfeitamente razoável, porque as classes aninhadas têm acesso privilegiado. Se fosse possível adicionar A :: C como uma classe aninhada da A , em seguida, A :: C poderia enganar A para conceder acesso a informações privilegiadas; e que yould violar o encapsulamento. É basicamente o mesmo que com a declaração friend: a declaração friend não lhe concede nenhum privilégio especial, que o seu amigo está se escondendo dos outros; ele permite que seus amigos para acessar informações que você está escondendo de seus não-amigos. Em C ++, chamar alguém de amigo é um ato altruísta, não um egoísta. O mesmo vale para permitir que uma classe para ser uma classe aninhada.

Som outros fatos sobre classes públicas aninhados:

  • escopo de A é candidato para símbolo de pesquisa de B : Se você não quer isso, make B um amigo de A em vez de uma classe aninhada. No entanto, há casos em que você quer exatamente este tipo de pesquisa símbolo.
  • A :: B não pode ser declarado para a frente : A e A :: B estão fortemente acoplados. Ser capaz de usar A :: B sem saber A só iria esconder esse fato.

Para resumir esta: se a ferramenta não atender às suas necessidades, não culpe a ferramenta; responsabilizar-se por utilizar a ferramenta; outros podem ter diferentes problemas, para os quais a ferramenta é perfeito.

paercebal disse tudo o que eu diria sobre enums aninhadas.

WRT aninhados aulas, meu comum e quase único caso de uso para eles é quando eu tenho uma classe que está manipulando um tipo específico de recurso, e eu preciso de uma classe de dados que representa algo específico para esse recurso. No seu caso, output_tray pode ser um exemplo bom, mas eu geralmente não usar classes aninhadas se a classe vai ter quaisquer métodos que vão ser chamado de fora da classe que contém, ou é mais do que primariamente uma classe de dados. Eu geralmente também não ninho classes de dados, a menos que a classe contida não é sempre directamente referenciada fora da classe que contém.

Assim, por exemplo, se eu tivesse uma classe printer_manipulator, ele pode ter uma classe contida por erros de manipulação de impressora, mas própria impressora seria uma classe não-contido.

Espero que isso ajude. :)

Lembre-se que você sempre pode promover uma classe aninhada para um de nível superior mais tarde, mas você pode não ser capaz de fazer o oposto sem quebrar o código existente. Portanto, meu conselho seria torná-lo uma classe aninhada em primeiro lugar, e se ele começa a se tornar um problema, torná-lo uma classe de nível superior na próxima versão.

Para mim um grande golpe para tê-lo fora é que se torna parte do namespace global. Se a classe enum ou relacionados realmente só se aplica à classe que está, então faz sentido. Assim, no caso da impressora, tudo o que inclui a impressora vai saber sobre ter acesso total ao PRINTER_TYPE enum, onde ele realmente não precisa de saber sobre isso. Eu não posso dizer que já usei uma classe interna, mas para um enum, este parece mais lógico para mantê-lo dentro. Como outro autor apontou, também é uma boa idéia para usar namespaces para agrupar itens semelhantes, uma vez que o entupimento do namespace global pode realmente ser uma coisa ruim. Eu tenho trabalhado anteriormente em projetos que são enormes e apenas trazendo-se uma lista completa auto no namespace global leva 20 minutos. Na minha opinião aninhados enums e classes namespaced / estruturas são provavelmente a abordagem mais limpa.

Eu concordo com as mensagens defendendo para a incorporação de seu enum em uma classe, mas há casos em que faz mais sentido para não fazer isso (mas, por favor, pelo menos, colocá-lo em um espaço de nomes). Se várias classes estão utilizando um enum definido dentro de uma classe diferente, em seguida, as classes são directamente dependentes de que outra classe de betão (que possui o enum). Isso certamente representa uma falha de projeto, uma vez que a classe será responsável por que enum, bem como outras responsabilidades.

Então, sim, incorporar o enum em uma classe se outro código utiliza apenas que enum para interagir diretamente com essa classe concreta. Caso contrário, encontrar um lugar melhor para manter o enum como um espaço de nomes.

Se você colocar o enum em uma classe ou um namespace, intellisense será capaz de lhe dar orientação quando você está tentando lembrar os nomes de enum. Uma pequena coisa é certa, mas às vezes as coisas pequenas da matéria.

Visual Studio 2008 não parece ser capaz de fornecer intellisense para classes aninhadas, então eu mudei para o idioma Pimpl na maioria dos casos em que eu costumava ter uma classe aninhada. Eu sempre colocar enums quer na classe, se for utilizado apenas por essa classe, ou fora da classe no mesmo namespace como a classe quando mais de uma classe usa o enum.

Eu posso ver um con para classes aninhadas, que se pode utilizar melhor programação genérica.

Se a pequena classe é definida fora da grande, você pode fazer a grande classe um modelo de classe e usar qualquer "pequeno" classe que você pode precisar no futuro, com grande classe.

Programação genérica é uma ferramenta poderosa, e, IMHO, devemos manter isso em mente ao desenvolver programas extensíveis. Estranho, que ninguém mencionou este ponto.

Apenas problema com classes aninhadas que topei ainda era que C ++ não permite-nos referir ao objeto da classe delimitador, nas funções de classe aninhados. Não podemos dizer "Encerrando :: este"

(Mas talvez haja uma maneira?)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top