FAQ Lite
Herança - private e protected

[ 24.1 ] Como você expressa herança private ?
[ 24.2 ] Até que ponto herança private e composição são similares?
[ 24.3 ] Qual das duas eu devo preferir: composição ou herança private ?
[ 24.4 ] Devo fazer conversão de tipo de uma classe derivada private para sua classe base?
[ 24.5 ] Herança protected é comparável à herança private ?
[ 24.6 ] Quais as regras de acesso para herança private e para
herança
protected ?

[ 24.1 ] Como você expressa herança private ?

Quando você usa : private ao invés de : public. Por exemplo:
    class Foo : private Bar {
    public:
      // ...
    }; 
Topo
[ 24.2 ] Até que ponto herança private e composição são similares?

Herança private é uma variante sintática de composição (tem-um).

Por exemplo, o relacionamento Car tem-um Engine pode ser expresso usando uma composição:

    class Engine {
    public:
      Engine(int numCylinders);
      void start();                 // Starts this Engine
    };
    
    class Car {
    public:
      Car() : e_(8) { }             // Initializes this Car with 8 cylinders
      void start() { e_.start(); }  // Start this Car by starting its Engine
    private:
      Engine e_;                    // Car has-a Engine
    }; 
O mesmo relacionamento tem-um pode ser expresso usando herança private:
    class Car : private Engine {    // Car has-a Engine
    public:
      Car() : Engine(8) { }         // Initializes this Car with 8 cylinders
      Engine::start;                // Start this Car by starting its Engine
    }; 
Há várias similaridades entre essas duas formas de composição:
  • Em ambos os casos há exatamente um membro Engine contido em um Car
  • Em nenhum dos dois casos os usuários da classe podem converter um Car* em um Engine*

Há também várias diferenças:

  • A primeira forma é necessária quando você quer conter várias Engines por Car
  • A segunda forma pode introduzir múltipla herança desnecessária
  • A segunda forma permite que membros de Car convertam um Car* para um Engine*
  • A segunda forma permite acesso aos membros protected: da classe base
  • A segunda forma permite que Car sobrescreva funções virtual de Engine

Repare que herança private é usada normalmente para se ter acesso aos membros protected: da classe base, mas é geralmente uma solução imediatista, um paliativo.

Topo
[ 24.3 ] Qual das duas eu devo preferir: composição ou herança private ?

Use composição quando você puder, use herança private quando você for obrigado.

Normalmente você não deveria querer ter acesso aos componentes internos de muitas outras classes, e herança private lhe dá um pouco desse poder extra, e responsabilidade extra também. Mas herança private não é uma solução abominável, é apenas mais cara de se manter, já que aumenta a probabilidade de que se altere algo que impacte código já existente.

Um uso legítimo, não imediatista, para herança private é quando você quer construir uma class Fred que usa código existente na class Wilma, e o código de class Wilma precisa invocar funções membro de sua nova class Fred. No caso presente, Fred chama funções não-virtual em Wilma, e Wilma chama funções próprias (usualmente virtuais puras), que foram sobrescritas por Fred. Esse talvez seja o caso mais difícil de se implementar com composição

    class Wilma {
    protected:
      void fredCallsWilma()
        {
          cout << "Wilma::fredCallsWilma()\n";
          wilmaCallsFred();
        }
      virtual void wilmaCallsFred() = 0;   // A pure virtual function
    };
    
    class Fred : private Wilma {
    public:
      void barney()
        {
          cout << "Fred::barney()\n";
          Wilma::fredCallsWilma();
        }
    protected:
      virtual void wilmaCallsFred()
        {
          cout << "Fred::wilmaCallsFred()\n";
        }
    }; 
Topo
[ 24.4 ] Posso fazer conversão de tipo de pointer de uma classe derivada private para sua classe base?

Geralmente não.

O relacionamento com a classe base é bem determinado a partir de uma função membro, ou de uma função friend da classe derivada. Assim, a conversão simples no sentido ascendente da hieraquia de classes, como PrivatelyDer* para Base* (ou PrivatelyDr& para Base&) é plenamente segura. Conversão de tipo de pointer nesse caso não é necessária e não é recomendada.  

Topo
[ 24.5 ] Herança protected é comparável à herança private ?

Semelhanças: ambas permitem sobrescrever funções virtual da classe base private/protected , sem exigência de que a classe derivada seja um tipo-de classe base.

Diferenças: herança protected permite que as classes derivadas de classes derivadas acessem todas as classes envolvidas no relacionamento de herança. Ou seja, as classes derivadas em segundo, terceiros ou mais níveis podem acessar os detalhes de implementação da classe base. Isso traz tanto benefícios quanto custos. Benefícios: subclasses de classes derivadas protected podem explorar o relacionamento com a classe base protected. Custos: as classes derivadas protected não podem modificar as características do   relacionamento de herança, sob pena de inviabilizar futuras classes derivadas.

Herança protected usa a sintaxe : protected

    class Car : protected Engine {
    public:
      // ...
    }; 
Topo
[ 24.6 ] Quais as regras de acesso para herança private e para
herança
protected ?

Tome as seguintes classes como exemplos:
    class B                    { /*...*/ };
    class D_priv : private   B { /*...*/ };
    class D_prot : protected B { /*...*/ };
    class D_publ : public    B { /*...*/ };
    class UserClass            { B b; /*...*/ }; 
  • Nenhuma das subclasses pode acessar nada que seja private em B.
  • Em D_priv, as partes public e protected de B são private.
  • Em D_prot, as partes public e protected de B são protected.
  • Em D_publ, as partes public de B são public e as partes protected de B são protected (D_publ é um tipo-de B).
  • class UserClass pode acessar apenas as partes public de B

Para tornar um membro public de B também public em D_priv ou em D_prot, declare o nome do membro com o prefixo B::

Por exemplo, para tornar o membro B::f(int,float) public em D_prot, você deve fazer:

    class D_prot : protected B {
    public:
      B::f;    // Note: Not B::f(int,float)
    }; 
Topo Anterior Próximo Índice
C++ FAQ Lite
Copyright © 1991-98 by Marshall Cline Ph.D., cline@parashift.com
Tradução: Dagoberto Haele Arnaut

| Home | Bookmarks | Universidades | Para Saber mais | Universidades | WEB Directory | Mapa do site |