Conforme
discutido no material de “Classes derivam classes”, a linguagem C++ oferece a possibilidade
de definirmos uma hierarquia de classes onde as classes mais gerais servem de
base para a definição de classes mais específicas (ou se o desenvolvimento for
“bottom-up”: a linguagem C++ permite que, a partir do agrupamento de classes
específicas, façamos a definição de classes mais gerais que podem “abrigar”
estrutura e comportamento comum às classes mais específicas). Não é o nosso
objetivo ensinar os métodos e técnicas de síntese e fatoramento de classes e
também não é nosso objetivo ensinar o desenho (ou “projeto”) de classes (“class
design”). No material abaixo vamos apenas discutir alguns aspectos sintáticos e
semânticos.
Muitas
vezes iremos definir classes para as quais não queremos que sejam criadas
instâncias. Podemos definir classes gerais apenas para facilitar o entendimento
ou apenas para definir qual é a estrutura e comportamento comum, e não há
sentido em definir instâncias. Considere o caso de definir uma classe Forma que
serve de base para Triangulo, Quadrado, etc Se quisermos sinalizar que esta
classe não deve ter instâncias basta definirmos a classe utilizando o que é
conhecido como uma uma “função virtual pura” (“pure virtual function”):
class A{public: virtual void f()=0;}
Observe que
no lugar do corpo da função temos o “pure specifier” (=0)Se tentarmos definir um objeto do
tipo A:
A x; //erro
Teremos o
seguinte erro de compilação:
cannot declare variable `x' to be of type `A'
because the following virtual functions are abstract: virtual void A::f()
Além de não
poder ser usada para definir objetos, não é possível usar a classe virtual ou
abstrata como tipo de parâmetro, como tipo para retorno, ou como tipo para
conversão explícita. A classe abstrata pode ser usada como o tipo alvo na definição
de ponteiros e referências:
A *p;
As funções
virtuais puras são herdadas e as classes herdeiras serão virtuais a menos que
façam a redefinição de cada função virtual pura herdada:
class A{public: virtual void f()=0;};
class B:public A{};
class C:public A{public: void f(){}};
Considerando as
definições do trecho de programa acima: podemos definir uma variável do tipo C
(pois houve a redefinição de f() com corpo vazio!) mas não podemos definir uma
variável do tipo B, pois B herdou a função virtual pura f() e não a redefiniu.