Compartilhar via


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

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

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

Objeto de linha de almoço simulado, 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

Componentes virtuais e de uma 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

Herança virtual e não virtual no layout do objeto

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 )

Consulte também

Referência

Várias classes base