Share via


Classes abstratas (C++)

As classes abstratas agem como expressões de conceitos gerais das quais classes mais específicas podem ser derivadas. Não é possível criar um objeto de um tipo de classe abstrata. No entanto, é possível usar ponteiros e referências para tipos de classe abstrata.

Você cria uma classe abstrata declarando pelo menos uma função membro virtual pura. Essa é uma função virtual declarada usando a sintaxe de especificador pure (= 0). Classes derivadas da classe abstrata devem implementar a função virtual pura, ou serão também classes abstratas.

Considere o exemplo apresentado em Funções virtuais. A intenção da classe Account é fornecer a funcionalidade geral, mas os objetos do tipo Account são muito gerais para serem úteis. Portanto, Account é um bom candidato para uma classe abstrata:

// deriv_AbstractClasses.cpp
// compile with: /LD
class Account {
public:
   Account( double d );   // Constructor.
   virtual double GetBalance();   // Obtain balance.
   virtual void PrintBalance() = 0;   // Pure virtual function.
private:
    double _balance;
};

A única diferença entre essa declaração e a anterior é que PrintBalance é declarado com o especificador puro (= 0).

Restrições sobre classes abstratas

As classes abstratas não podem ser usadas para:

  • Variáveis ou dados de membro

  • Tipos de argumento

  • Tipos de retorno de função

  • Tipos de conversões explícitas

Outra restrição é que se o construtor para uma classe abstrata chamar uma função virtual pura, direta ou indiretamente, o resultado será indefinido. No entanto, os construtores e os destruidores para classes abstratas podem chamar outras funções de membro.

Funções virtual puras definidas

Funções virtuais puras em classes abstratas podem ser definidas ou ter uma implementação. Você só pode chamar essas funções usando a sintaxe totalmente qualificada:

abstract-class-name::function-name()

As funções virtuais puras definidas são úteis quando você projeta hierarquias de classe cujas classes base incluem destruidores virtuais puros. Isso ocorre porque os destruidores de classe base são sempre chamados durante a destruição de objetos. Considere o seguinte exemplo:

// deriv_RestrictionsOnUsingAbstractClasses.cpp
// Declare an abstract base class with a pure virtual destructor.
// It's the simplest possible abstract class.
class base
{
public:
    base() {}
    // To define the virtual destructor outside the class:
    virtual ~base() = 0;
    // Microsoft-specific extension to define it inline:
//  virtual ~base() = 0 {};
};

base::~base() {} // required if not using Microsoft extension

class derived : public base
{
public:
    derived() {}
    ~derived() {}
};

int main()
{
    derived aDerived; // destructor called when it goes out of scope
}

O exemplo mostra como uma extensão de compilador da Microsoft permite adicionar uma definição embutida à ~base() virtual pura. Você também pode definir fora da classe usando base::~base() {}.

Quando o objeto aDerived sai do escopo, o destruidor da classe derived é chamado. O compilador gera código para chamar implicitamente o destruidor para a classe base após o destruidor derived. A implementação vazia para a função virtual pura ~base garante que pelo menos uma implementação exista para a função. Sem ela, o vinculador gera um erro de símbolo externo não resolvido para a chamada implícita.

Observação

No exemplo anterior, a função virtual pura base::~base é chamada implicitamente de derived::~derived. Também é possível chamar funções virtuais puras explicitamente usando um nome de função membro totalmente qualificado. Essas funções devem ter uma implementação, ou a chamada resulta em um erro em tempo de vinculação.

Confira também

Herança