Quais são seus critérios de decisão em C ++ para criar algo como membro de dados ou método virtual?

5

(Achei que isso era muito subjetivo para SO, então postar aqui ...)

Eu tenho alguns comportamentos que posso implementar de várias maneiras. Pelo menos dois métodos são mostrados no snippet de código abaixo. Presuma que o membro de dados m_well esteja corretamente configurado de alguma forma no momento da construção do objeto.

struct Behavior
{
    virtual bool behavesWell() { return true; }

private:
    bool m_well;
public:
    bool behavesMemberWell() { return m_well; }
};

struct OtherBehavior : public Behavior
{
    virtual bool behavesWell() { return false; }
};

Obviamente, o método depende do despacho virtual, e o outro é meramente o retorno de um membro de dados.

Um terceiro método não mostrado provavelmente teria a função de membro público não-virtual não retornando um membro de dados fixo, mas chamando um virtual - vamos deixar isso de lado para o propósito disso, por favor.

O que o levaria a um ou outro desses dois métodos de implementação de funcionalidade, de modo que um usuário dessa classe possa interrogar o comportamento de um objeto?

    
por sdg 13.12.2010 / 20:52
fonte

6 respostas

3

Tanto quanto eu posso ver, você tem alguns problemas conflitantes aqui, o que pode ser esclarecido se você pudesse nos dizer com que propósito você está fazendo isso? O código será usado por você / sua equipe ou você está projetando uma API para consumo por outras pessoas?

Se você está apenas tentando projetar uma boa interface para sua funcionalidade, coloque-se no lugar dos clientes de suas funções - escreva alguns testes de unidade. Se ao escrever os testes de unidade, qualquer coisa parecer estranha ou não óbvia, seu design precisa ser melhorado.

Se sua classe é destinada à subclasse, você não deseja membros de dados públicos ou membros de dados protegidos. Os membros de dados que são privados podem ser alterados a qualquer momento sem quebrar as subclasses, enquanto as alterações nos membros protegidos (potencialmente) interrompem as subclasses e as alterações nos membros de dados públicos (muito provavelmente) quebram o código do cliente. Pode parecer tedioso ter um par getter / setter de métodos para manipular um membro de dados, mas vale a pena se você quiser manter a implementação flexível e não se projetar em um canto.

Os métodos virtuais indicam que você está considerando entregar ao cliente da sua classe uma interface que seria virtual pura. Se este for o caso, então você não pode ter membros de dados em uma classe abstrata (virtual pura), o que leva você a métodos virtuais com chamadas de método virtual para obter / definir itens de dados.

    
por 14.12.2010 / 00:42
fonte
2

Temos algumas classes que funcionam dessa maneira - existe um tipo de função que retorna algo diferente em diferentes subclasses. O problema que tenho é que não há uma boa maneira de dizer dentro do depurador, dado um BaseClass * .

Use uma variável de membro. O próximo cara a trabalhar no código pode agradecer-lhe.

    
por 13.12.2010 / 23:21
fonte
0

No seu exemplo, eu usaria um membro de dados. É simples e direto.

Eu usaria um método virtual onde o comportamento da função realmente muda na classe derivada. No seu exemplo, ele ainda está retornando um booleano, mesmo que o valor seja diferente. Métodos para mim devem estar realizando algo - computação ou E / S ou o que você tem - não apenas sendo uma interface obtusa para dados.

    
por 13.12.2010 / 21:06
fonte
0

A regra geral é que todos os seus membros de dados devem ser privados. Há exceções a essa regra, como simples strings POD (planície de dados antigos) que são apenas passadas ou armazenadas, mas, na maioria das vezes, faz sentido manter todos os membros de dados privados.

Se você precisar que outros objetos acessem o acesso de leitura a um membro de dados, você escreverá um getter. Se sua classe não tiver classes derivadas dela, então não há necessidade de tornar o getter virtual. A única vez que você precisa tornar qualquer função membro virtual, é quando você deseja permitir que uma classe derivada a substitua.

    
por 13.12.2010 / 22:00
fonte
0
  • virtual bool behavesWell() incorre em sobrecarga extra de processamento, mas, geralmente, não é um problema (por exemplo, funções virtuais e desempenho - C ++ ).

  • bool behavesMemberWell() tem requisitos adicionais de armazenamento: você tem um bool m_well extra em todos os objetos criados. Com a primeira abordagem, você só tem um ponteiro adicional na vtable (uma vez por classe).

Se a classe Behavior puder ter mais de uma função virtual, prefiro a primeira abordagem (função virtual).

    
por 27.06.2015 / 16:37
fonte
0

Se eu quero expor dados brutos ou não, pode ser determinado por uma regra simples: o escopo / visibilidade do membro de dados. A ocultação de informações é, em última instância, reduzir o escopo / visibilidade para ajudar a manter invariantes. Naturalmente, se você tem uma classe que expõe os membros de dados públicos, mas a classe é usada apenas em uma pequena parte do sistema, o escopo do membro de dados já é muito pequeno. Tentando reduzir ainda mais poderia ser um exagero.

Como o seu caso envolve herança, você deve questionar não apenas quantos locais seus campos de dados serão expostos até onde os clientes forem, mas também quantas subclasses você terá desde que você estaria expondo esse campo de dados. -los para mexer também.

Agora, especificamente no que diz respeito ao despacho dinâmico, um conselho geral que eu ofereço é que nunca se preocupe com o desempenho do despacho dinâmico até que, de fato, se mostre um hotspot. É uma das maneiras mais fáceis de tornar seu código desnecessariamente mais difícil de manter, obcecado com o custo das chamadas de função indiretas. É claro que std::sort é muito mais rápido que qsort porque pode evitar chamadas de função indireta para o comparador, mas é um caso patológico em que classificar um milhão de elementos pode invocar 50 milhões de chamadas de função indiretas, todas realizando uma quantidade trivial de trabalho. / p>

Portanto, sua decisão aqui deve ter muito pouco a ver com o desempenho e muito mais com a manutenção. Além disso, a função virtual tem o benefício de permitir que você faça alguns cálculos para determinar se esses comportamentos "comportam-se". Não tenho certeza se isso é um benefício prático ou não no seu caso.

    
por 17.12.2017 / 08:52
fonte

Tags