Pergunta

Alguém me contou sobre um C ++ diferença de estilo em sua equipe. Eu tenho meu próprio ponto de vista sobre o assunto, mas eu estaria interessado pelo pros e contras vindo de todos.

Assim, caso você tem uma propriedade de classe que você deseja expor através de dois getters, uma leitura / gravação, e o outro, somente leitura (ou seja, não existe um método definido). Há pelo menos duas maneiras de fazer isso:

class T ;

class MethodA
{
   public :
      const T & get() const ;
      T & get() ;

      // etc.
} ;

class MethodB
{
   public :
      const T & getAsConst() const ;
      T & get() ;

      // etc.
} ;

Quais seriam os prós e os contras de cada método?

Estou interessado mais por razões técnicas / semântica C ++, mas razões de estilo são bem-vindos também.

Note que MethodB tem um grande problema técnico. (Dica: em código genérico)

Foi útil?

Solução

Bem, para uma coisa, getAsConst deve ser chamado quando o ponteiro 'this' é const - não quando você deseja receber um objeto const. Então, juntamente com quaisquer outras questões, é sutilmente misnamed. (Você ainda pode chamá-lo quando 'isto' é não-const, mas que não é nem aqui nem lá.)

Ignorando isso, getAsConst você ganha nada, e coloca uma sobrecarga para o desenvolvedor usando a interface. Em vez de apenas chamar "pegar" e sabendo que ele está recebendo o que ele precisa, agora ele tem que verificar a existência ou não ele está usando atualmente uma variável const, e se o novo objeto que ele está agarrando precisa ser const. E depois, se ambos os objetos se tornam não-const devido a alguma refatoração, ele tem que mudar a sua chamada.

Outras dicas

C ++ deve ser perfeitamente capaz de lidar com o método A em quase todas as situações. Eu sempre usá-lo, e eu nunca tive um problema.

Método B é, na minha opinião, um caso de violação de OnceAndOnlyOnce. E, agora você precisa ir descobrir se você está lidando com referência const para escrever o código que compila primeira vez.

Eu acho que isso é uma coisa estilística - Tecnicamente ambas as obras, mas MethodA faz com que o compilador para trabalhar um pouco mais. Para mim, é uma coisa boa.

Pessoalmente, eu prefiro o primeiro método, porque ele faz para uma interface mais consistente. Além disso, para me getAsConst () soa quase tão tolo quanto getAsInt ().

Em uma nota diferente, você realmente deve pensar duas vezes antes de retornar uma referência não-const ou um ponteiro não-const para um membro de dados de sua classe. Este é um convite para as pessoas a explorar o funcionamento interno de sua classe, que, idealmente, deve ser escondido. Em outras palavras ele quebra o encapsulamento. Gostaria de usar um const get () e um conjunto () e retornar uma referência não-const somente se não houver nenhuma outra maneira, ou quando ele realmente faz sentido, de modo a dar acesso de leitura / gravação para um elemento de uma matriz ou uma matriz.

Dado o estilo de jogo precedente pela biblioteca padrão (ou seja, begin () e começar () const para citar apenas um exemplo), deve ser óbvio que o método A é a escolha correta. Eu questiono a sanidade da pessoa que método escolhe B.

Assim, o primeiro estilo é geralmente preferível.

Nós usamos uma variação do segundo estilo um pouco na base de código que eu estou trabalhando atualmente em embora, porque queremos uma grande distinção entre const e uso não-const.

No meu exemplo específico, temos getTessellation e getMutableTessellation. Ele é implementado com um ponteiro copy-on-write. Por motivos de desempenho, queremos a versão const para ser usado sempre que possível, de modo que fazer o nome mais curto, e nós torná-lo um nome diferente para que as pessoas não acidentalmente causa uma cópia quando eles não estavam indo para escrever de qualquer maneira.

Embora pareça a sua pergunta aborda apenas um método, eu ficaria feliz em dar o meu contributo no estilo. Pessoalmente, por razões de estilo, eu prefiro a primeira. A maioria das IDEs irá aparecer a assinatura tipo de funções para você.

Eu prefiro a primeira. Parece melhor no código quando duas coisas que, essencialmente, fazer o mesmo olhar coisa o mesmo. Além disso, é raro para que você tenha um objeto não-const, mas quero chamar o método const, de modo que não é muito de um consern (e no pior dos casos, você só precisa de um const_cast <>).

O primeiro permite alterações para o tipo de variável (se é const ou não) sem qualquer outra modificação do código. Claro, isso significa que não há nenhuma notificação para o desenvolvedor que isso poderia ter mudado a partir do caminho pretendido. Então, é realmente se você valoriza a ser capaz de rapidamente refatorar, ou ter a rede de segurança extra.

O segundo é algo relacionado a notação húngara que eu pessoalmente NÃO como isso vou ficar com o início método.

Eu não gosto de notação húngara, porque acrescenta redundância que eu normalmente detesto na programação. É apenas a minha opinião.

Uma vez que você esconde os nomes das classes, este alimento para o pensamento sobre o estilo pode ou não se aplicam:

Será que faz sentido dizer a esses dois objetos, MethodA e MethodB, para "ficar" ou "getAsConst"? Você enviar "pegar" ou "getAsConst", como mensagens para qualquer objeto?

A forma como eu vejo, como o remetente da mensagem / invocador do método, você é o único recebendo o valor; por isso, em resposta a este "get" mensagem, você está enviando alguma mensagem para MethodA / MethodB, cujo resultado é o valor que você precisa para começar.

Exemplo:. Se o chamador de MethodA é, digamos, um serviço em SOA, e MethodA é um repositório, em seguida, dentro get_A do serviço (), chamar MethodA.find_A_by_criteria (...)

A principal desvantagem tecnológica da MethodB eu vi é que ao aplicar o código genérico para isso, devemos dobrar o código para manipular tanto o const e a versão não-const. Por exemplo:

digamos Vamos T é um objeto fim-capazes (ou seja, podemos comparar a objetos do tipo T com operador <), e vamos dizer que queremos encontrar o máximo entre duas MethodA (resp. Dois MethodB).

Para MethodA, todos nós precisamos de código é:

template <typename T>
T & getMax(T & p_oLeft, T & p_oRight)
{
   if(p_oLeft.get() > p_oRight.get())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

Este código irá funcionar tanto com objetos const e objetos não-const de tipo T:

// Ok
const MethodA oA_C0(), oA_C1() ;
const MethodA & oA_CResult = getMax(oA_C0, oA_C1) ;

// Ok again
MethodA oA_0(), oA_1() ;
MethodA & oA_Result = getMax(oA_0, oA_1) ;

O problema surge quando queremos aplicar este código fácil de algo seguindo a convenção MethodB:

// NOT Ok
const MethodB oB_C0(), oB_C1() ;
const MethodB & oB_CResult = getMax(oB_C0, oB_C1) ; // Won't compile

// Ok
MethodA oB_0(), oB_1() ;
MethodA & oB_Result = getMax(oB_0, oB_1) ;

Para o MethodB ao trabalho em ambos const e versão não-const, devemos tanto para uso do já definido getMax, mas adicionar a ele a seguinte versão de getMax:

template <typename T>
const T & getMax(const T & p_oLeft, const T & p_oRight)
{
   if(p_oLeft.getAsConst() > p_oRight.getAsConst())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

Conclusão, por não confiar o compilador sobre o uso const-ness, nós nos sobrecarregar com a criação de duas funções genéricas quando se deveria ter sido suficiente.

Claro que, com a paranóia o suficiente, a função de modelo secondth deveria ter sido chamado getMaxAsConst ... E assim, o problema seria propagar-se através de todo o código ...

: - p

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