Classes de base virtuais
Porque uma classe pode ser uma classe base indireta a uma classe derivada mais de uma vez, C++ fornece uma maneira de otimizar a forma como funcionam as classes base. As classes base virtuais oferecem uma maneira de economizar espaço e evitar ambiguidades nas hierarquias de classes que usam a herança múltipla.
Cada objeto não virtual contém uma cópia dos membros de dados definidos na classe base. Essa duplicação perde espaço e exige que você especifique que cópia dos membros da classe base você quer sempre que os acessa.
Quando uma classe base é especificada como base virtual, ela pode atuar como uma base indireta mais de uma vez sem duplicação de seus membros de dados. Uma única cópia dos membros de dados é compartilhada por todas as classes base que ela usa como base virtual.
Ao declarar uma classe base virtual, a palavra-chave virtual aparece nas listas de base das classes derivadas.
Considere a hierarquia de classes na figura a seguir, que ilustra uma linha simulada de almoço.
Gráfico de linha de almoço simulado
Na figura, Queue é a classe base para CashierQueue e LunchQueue. No entanto, quando as duas classes são combinadas para formar LunchCashierQueue, o seguinte problema ocorre: a nova classe contém dois subobjetos do tipo Queue, um de CashierQueue e o outro de LunchQueue. A figura a seguir mostra o layout conceitual de memória (o layout real de memória pode ser otimizado).
Objeto de linha de almoço simulado
Observe que há dois subobjetos Queue no objeto LunchCashierQueue. O código a seguir declara Queue como uma classe base virtual:
// deriv_VirtualBaseClasses.cpp
// compile with: /LD
class Queue {};
class CashierQueue : virtual public Queue {};
class LunchQueue : virtual public Queue {};
class LunchCashierQueue : public LunchQueue, public CashierQueue {};
A palavra-chave virtual garante que apenas uma cópia do subobjeto Queue seja incluída (veja a figura a seguir).
Objeto de linha de almoço simulado com classes base virtuais
Uma classe pode ter um componente virtual e um componente não virtual de determinado tipo. Isso acontece nas condições ilustradas na figura a seguir.
Componentes virtuais e não virtuais da mesma classe
Na figura, CashierQueue e LunchQueue usam Queue como uma classe base virtual. No entanto, TakeoutQueue especifica Queue como uma classe base, não uma classe base virtual. Portanto, LunchTakeoutCashierQueue tem dois subobjetos do tipo Queue: um do caminho de herança que inclui LunchCashierQueue e outro do caminho que inclui TakeoutQueue. Isso é ilustrado na figura a seguir.
Layout de objeto com herança virtual e não virtual
Dica
A herança virtual oferece benefícios significativos de tamanho quando comparada com a herança não virtual.No entanto, pode apresentar a sobrecarga adicional de processamento.
Se uma classe derivada substitui uma função virtual que herda de uma classe base virtual e, se um construtor ou um destruidor para a classe base derivada chamar essa função usando um ponteiro para a classe base virtual, o compilador virtual poderá inserir campos “vtordisp” adicionais ocultos nas classes com bases virtuais. A opção do compilador /vd0 suprime a adição do membro oculto de deslocamento do construtor/destruidor vtordisp. A opção do compilador /vd1, padrão, habilita esses campos quando são necessários. Desative vtordisps apenas se você tiver certeza de que todos os destruidores e construtores da classe chamam funções virtuais virtualmente.
A opção do compilador /vd afeta um módulo de compilação inteiro. Use o pragma vtordisp para suprimir e habilitar novamente os campos vtordisp classe por classe:
#pragma vtordisp( off )
class GetReal : virtual public { ... };
#pragma vtordisp( on )