Pergunta

No (não) excelente livro C ++ Coding Standards , ponto 44, intitulado "Prefere escrever funções não-membro nonfriend" , Sutter e Alexandrescu recomendam que apenas as funções que realmente precisam de acesso aos membros de uma classe ser eles mesmos membros dessa classe. Todas as outras operações que podem ser escritas usando apenas as funções de membro não deve ser parte da classe. Eles devem ser não-membros e não-amigos. Os argumentos são os seguintes:

  • Promove encapsulamento, porque há menos código que precisa acessar as partes internas de uma classe.
  • Não faz escrever modelos de função mais fácil, porque você não tem que adivinhar cada vez que se alguma função é membro ou não.
  • Ele mantém a pequena classe, que por sua vez faz com que seja mais fácil de testar e manter.

Apesar de eu ver o valor nestes argumentos, vejo uma enorme desvantagem: meu IDE não pode me ajudar a encontrar estas funções Sempre que tenho um objeto de algum tipo, e eu quero ver! que estão disponíveis nele operações, não pode simplesmente digitar "pMysteriousObject->" e obter uma lista de funções membro mais.

Manter um design limpo é no final sobre como fazer sua vida de programação mais fácil. Mas isso iria realmente fazer o meu muito mais difícil.

Então, eu estou querendo saber se é realmente vale a pena. Como você lida com isso?

Foi útil?

Solução

Eu vou ter que discordar com Sutter e Alexandrescu em um presente. Eu acho que se o comportamento da função foo() se insere no âmbito das responsabilidades da classe de Bar, então foo() deve ser parte de bar().

O fato de que foo() não precisa de acesso direto aos dados membros da Bar não significa que ele não é conceitualmente parte de Bar. Também pode significar que o código é bem consignado. Não é incomum ter funções membro que executam todo o seu comportamento através de outras funções de membro, e eu não vejo por que deveria ser.

Concordo plenamente que as funções periféricas relacionadas-deve não fazer parte da classe, mas se algo é fundamental para as responsabilidades da classe, não há nenhuma razão que não deve ser um membro, independentemente de ela está diretamente perder tempo com os dados dos membros.

Quanto a estes pontos específicos:

Promove encapsulamento, porque há menos código que precisa acessar as partes internas de uma classe.

Na verdade, os menos funções que acessam diretamente os internos, melhor. Isso significa que com funções membro fazer, tanto quanto possível via outras funções membro é uma coisa boa. Dividindo funções bem fatorado fora da classe só deixa você com uma meia-classe, que exige um monte de funções externas para ser útil. Puxando funções bem fatorados longe de suas aulas também parece desencorajar a escrita de funções bem fatorados.

Faz escrever modelos de função mais fácil, porque você não tem que adivinhar cada vez que se alguma função é membro ou não.

Eu não entendo tudo isso. Se você puxar um monte de funções fora de aulas, você empurrou mais responsabilidade em modelos de função. Eles são forçados a assumir que ainda menos funcionalidade é fornecida por seus argumentos de modelo de classe, a menos que nós estamos indo supor que a maioria das funções extraídos de suas aulas vai ser convertida em um modelo (ugh).

Ele mantém a pequena classe, que por sua vez faz com que seja mais fácil de testar e manter.

Hum, claro. Ele também cria uma série de funções adicionais, externos para testar e manter. Eu não consigo ver o valor desta.

Outras dicas

Scott Meyers tem uma opinião semelhante à Sutter, consulte aqui .

Ele também afirma claramente o seguinte:

"Com base em seu trabalho com vários corda-como aulas, Jack Reeves observou que algumas funções só não 'sensação' direita quando fez não-membros, mesmo se eles poderiam ser não-membros não-amigo . o "melhor" interface para uma classe só pode ser encontrada através do equilíbrio entre muitos interesses concorrentes, dos quais o grau de encapsulamento é apenas um ".

Se uma função seria algo que "só faz sentido" ser uma função membro, torná-lo um. Da mesma forma, se não é realmente parte da interface principal, e "só faz sentido" para ser um não-membro, fazer isso.

Uma nota é que, com versões sobrecarregadas de eg operador == (), as estadias de sintaxe o mesmo. Então, neste caso, você não tem nenhuma razão não para torná-lo um não-amigo não-membro função flutuante declarou no mesmo lugar como a classe, a menos que ele realmente precisa de acesso a membros privados (na minha experiência, raramente). E mesmo assim, você pode definir operador! = () Um não-membro e em termos de operador == ().

Eu não acho que seria errado dizer que entre eles, Sutter, Alexandrescu, e Meyers ter feito mais para a qualidade de C ++ que qualquer outra pessoa.

Uma simples pergunta que eles pedem é:

Se uma função de utilidade tem duas classes independentes como parameteres, que classe deve a função "próprio" membro?

Outra questão, é que você só pode adicionar funções de membro onde a classe em questão está sob seu controle. Quaisquer funções auxiliares que você escreve para std :: string terá que ser não-membros desde que você não pode voltar a abrir a definição de classe.

Para ambos os exemplos, o IDE irá fornecer informações incompletas, e você terá que usar a "maneira antiga".

Dado que os especialistas mais influentes C ++ no mundo consideram que as funções não-associados com uma classe parâmetro fazem parte da interface de aulas, este é mais um problema com o seu IDE em vez do estilo de codificação.

O IDE provavelmente vai mudar em um comunicado ou dois, e você pode até ser capaz de levá-los para adicionar esta funcionalidade. Se você mudar seu estilo de codificação para hoje terno IDE, você pode muito bem achar que você tem problemas maiores no futuro com código improrrogável / insustentável.

É verdade que funções externas não deve ser parte da interface. Em teoria, a classe deve conter apenas os dados e expor a interface para funções utilitárias que ele se destina e não. Adicionando funções de utilidade para a interface apenas crescer a base de código classe e torná-lo menos sustentável. Eu atualmente manter uma classe com cerca de 50 métodos públicos, que é simplesmente insano.

Agora, na realidade, concordo que isso não é fácil de aplicar. Muitas vezes é mais fácil simplesmente adicionar outro método para a sua classe, ainda mais se você estiver usando uma IDE que realmente pode simplesmente adicionar um novo método para uma classe existente.

A fim de manter minhas aulas simples e ainda ser capaz de centralizar a função externa, muitas vezes eu usar a classe utilitário que funciona com minha classe, ou mesmo namespaces. Gostaria de começar por criar a classe que irá envolver meus dados e expor a mais simples interface do possível. Eu, então, criar uma nova classe para cada tarefa que eu tenho a ver com a classe.

Exemplo: criar uma classe Point, em seguida, adicione um PointDrawer classe para desenhá-lo a um bitmap, PointSerializer para salvá-lo, etc

.

Se você lhes der um prefixo comum, então talvez o seu IDE vai ajudar se você digitar

::prefix

ou

namespace::prefix

Em muitas linguagens OOP métodos não-classe não-amigo são cidadãos de terceira classe que residem em um orfanato alheio a qualquer coisa. Quando eu escrever um método, eu gosto de escolher bons pais - uma classe montagem - onde eles têm as melhores chances para se sentir bem-vindo e ajuda

.

Eu teria pensado que o IDE foi realmente ajudando-lo.

O IDE está escondendo as funções protegidas na lista porque não estão disponíveis para o public , assim como o designer da classe destina-se .

Se você estivesse dentro do escopo da classe e digitou isso -.> seguida, as funções protegidas seria exibido na lista

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