Última atualização:2026-10-13
Funções virtuais em C++¶
Sobre o autor:¶
Conta pública pessoal no WeChat:

1. Funções virtuais e polimorfismo em tempo de execução¶
Código correspondente: emp.cpp
A chamada de uma função virtual depende do tipo do objeto apontado ou referenciado, e não do tipo do próprio ponteiro ou referência.
2. vptr e vtable¶
Veja vptr e vtable
3. Argumentos padrão em funções virtuais¶
Código correspondente: default_arg.cpp
Os argumentos padrão são vinculados estaticamente, enquanto as funções virtuais são vinculadas dinamicamente. Qual argumento padrão será usado depende do tipo do próprio ponteiro ou referência, e não do tipo do objeto.
4. Pode ou não pode¶
(1) Uma função estática pode ser declarada virtual?
Há dois motivos principais:
Uma função estática não pode ser declarada virtual, nem pode ser qualificada com as palavras-chave const e volatile
Uma função-membro static não pertence a nenhum objeto ou instância da classe, portanto adicionar virtual a essa função não tem nenhum significado.
As funções virtuais dependem do vptr e da vtable. O vptr é um ponteiro, criado no construtor da classe, e só pode ser acessado por meio do ponteiro this; as funções-membro estáticas não têm ponteiro this e, por isso, não conseguem acessar o vptr.
Código para estudo: static_error.cpp
(2) Um construtor pode ser virtual?
Um construtor não pode ser declarado virtual. Além disso, com exceção de inline e explicit, um construtor não permite o uso de nenhuma outra palavra-chave.
Por que um construtor não pode ser virtual?
Embora a tabela de funções virtuais (vtable) já seja construída na fase de compilação, o ponteiro para a tabela de funções virtuais (vptr) só é gerado em tempo de execução, quando o objeto é instanciado. Se uma classe contém funções virtuais, o compilador adiciona no construtor o código que cria o vptr. Aí está o problema: se o construtor fosse virtual, ele precisaria do vptr para acessar a vtable, mas nesse momento o vptr ainda não existe. Portanto, um construtor não pode ser virtual.
Usamos funções virtuais porque precisamos de despacho polimórfico com informação incompleta. Já o construtor serve para inicializar uma instância, e o tipo da instância precisa ser definido. Por isso não há necessidade de declarar um construtor como virtual.
Código para estudo:
(3) Um destrutor pode ser virtual?
Um destrutor pode ser declarado virtual. Se precisarmos excluir por meio de um ponteiro da classe base um objeto de uma classe derivada, o destrutor deve ser declarado virtual. Na verdade, sempre que uma classe puder ser herdada por outras classes, deve-se declarar um destrutor virtual (mesmo que esse destrutor não faça nada).
Código para estudo:
(4) Uma função virtual pode ser privada?
- Quando um ponteiro da classe base aponta para um objeto da classe derivada, a função do objeto da classe derivada é chamada;
- int main() deve ser declarado friend da classe Base, caso contrário a compilação falha. O compilador informa: ptr não consegue acessar a função privada. É claro que, se a classe base for declarada public e a derivada private, o problema deixa de existir.
Código para estudo:
(5) Uma função virtual pode ser inline?
Normalmente o compilador considera se vai tornar inline as funções-membro de uma classe. Mas uma função virtual chamada por meio de um ponteiro ou referência à classe base jamais pode ser inlined. É claro que, quando uma função virtual é chamada em um objeto real ou de forma estática, ela pode ser inlined, e a chamada estática de um destrutor virtual certamente será expandida inline.
- Uma função virtual pode ser uma função inline; inline pode qualificar uma função virtual, mas uma função virtual não pode ser inlined quando exibe comportamento polimórfico.
- O inlining é uma sugestão ao compilador em tempo de compilação, enquanto o polimorfismo das funções virtuais ocorre em tempo de execução; o compilador não pode saber qual código será chamado em tempo de execução, por isso uma função virtual não pode ser inlined quando se comporta polimorficamente (em tempo de execução).
- O único caso em que
inline virtualpode ser inlined é quando o compilador sabe a qual classe pertence o objeto chamado (por exemploBase::who()), o que só acontece quando o compilador tem o objeto real, e não um ponteiro ou referência para o objeto.
Código para estudo:
5. RTTI e dynamic_cast¶
RTTI (Run-Time Type Identification, identificação de tipo em tempo de execução) permite que um programa, por meio de um ponteiro ou referência a uma classe base, verifique o tipo real da classe derivada do objeto apontado.
Na programação orientada a objetos, às vezes precisamos consultar em tempo de execução se um objeto pode ser usado como um determinado tipo polimórfico. De modo semelhante ao instanceof do Java e aos operadores as e is do C#, o C++ oferece dynamic_cast para conversão dinâmica. Em comparação com as conversões forçadas no estilo C e com o reinterpret_cast do C++, o dynamic_cast fornece verificação de segurança de tipos e é uma conversão baseada em consulta de capacidade (Capability Query); por isso, o dynamic_cast é a escolha recomendada para conversões entre tipos polimórficos.
Código para estudo:
6. Funções virtuais puras e classes abstratas¶
Veja Funções virtuais puras e classes abstratas
Tópicos relacionados¶
- Funções virtuais puras e classes abstratas em C++ | C++那些事
- Asserções com assert em C++ | C++那些事
- Bit fields em C++ | C++那些事
- Implementando polimorfismo de C++ em linguagem C | C++那些事
- const em C++ explicado: constantes, ponteiro const vs ponteiro para const | C++那些事
- A família completa do const em C++ | C++那些事
- O operador de desreferência * em C++ | C++那些事
- Inicialização e atribuição em C++ | C++那些事
- Formas de retornar múltiplos valores em C++ | C++那些事
- A palavra-chave mutable em C++ | C++那些事