Última atualização:2026-10-12
Funções virtuais (virtual) em C++¶
Sobre o autor:¶
Conta oficial do WeChat:

1.Funções virtuais e polimorfismo em tempo de execução¶
O código correspondente está em: 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_vtable那些事
3.Argumentos padrão em funções virtuais¶
O código correspondente está em: default_arg.cpp
Os argumentos padrão têm vinculação estática, enquanto as funções virtuais têm vinculação dinâmica. O uso de argumentos padrão depende do tipo do próprio ponteiro ou referência, e não do tipo do objeto.
4.O que pode e o que não pode¶
(1) Uma função estática pode ser declarada virtual?
Há dois motivos principais:
Funções estáticas não podem ser declaradas virtuais e tampouco podem ser modificadas pelas palavras-chave const e volatile
As funções membro static não pertencem a nenhum objeto ou instância de classe; portanto, adicionar virtual a tal função não teria qualquer sentido.
As funções virtuais dependem do vptr e do vtable para funcionar. O vptr é um ponteiro, criado no construtor da classe, que só pode ser acessado por meio do ponteiro this; como as funções membro estáticas não têm o ponteiro this, elas não conseguem acessar o vptr.
Código para estudo: static_error.cpp
(2) Um construtor pode ser virtual?
Construtores não podem ser declarados virtuais. Além disso, exceto inline e explicit, construtores não aceitam nenhuma outra palavra-chave.
Por que o 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 na fase de execução, quando o objeto é instanciado. Se a classe tiver funções virtuais, o compilador adiciona no construtor o código para criar 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. Por isso, o construtor não pode ser uma função virtual.
Usamos funções virtuais porque precisamos de execução polimórfica com informação incompleta; já o construtor serve para inicializar a instância, e o tipo da instância deve ser bem definido. Portanto, não há necessidade de declarar o construtor como função virtual.
Código para estudo:
(3) Um destrutor pode ser virtual?
Destrutores podem ser declarados virtuais. Se precisarmos excluir um ponteiro de classe base que aponta para uma classe derivada, devemos declarar o destrutor como função virtual. Na verdade, sempre que uma classe puder ser herdada por outra, deve-se declarar um destrutor virtual (mesmo que esse destrutor não execute nenhuma operação).
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, é chamada a função do objeto da classe derivada;
- int main() deve ser declarado amigo (friend) da classe Base, caso contrário a compilação falha. O compilador reporta: ptr não consegue acessar a função privada. Naturalmente, se a classe base for declarada public e a classe derivada private, o problema deixa de existir.
Código para estudo:
(5) Uma função virtual pode ser inlined?
Normalmente, o compilador considera se cada função membro da classe deve ser inlined. Mas funções virtuais chamadas por meio de ponteiro ou referência da classe base definitivamente não podem ser inlined. Naturalmente, quando um objeto concreto chama uma função virtual, ou quando a chamada é estática, a inlining é possível; a chamada estática de um destrutor virtual também certamente será expandida inline.
- Uma função virtual pode ser uma função inline: inline pode modificar funções virtuais, mas quando a função virtual manifesta polimorfismo, ela não pode ser inlined.
- A inlining é uma sugestão ao compilador para inlinear no momento da compilação, enquanto o polimorfismo da função virtual ocorre em tempo de execução; o compilador não consegue saber qual código será chamado em tempo de execução; por isso, quando a função virtual se comporta polimorficamente (em tempo de execução), ela não pode ser inlined.
inline virtualsó pode ser inlined quando o compilador sabe de qual classe é o objeto chamado (como emBase::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): com a informação de tipo em tempo de execução, o programa consegue usar um ponteiro ou uma referência da classe base para verificar o tipo derivado real do objeto apontado por esses ponteiros ou referências.
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 forma semelhante ao instanceof do Java e aos operadores as e is do C#, o C++ oferece a função dynamic_cast para conversão dinâmica. Comparada à conversão forçada estilo C e ao reinterpret_cast do C++, a dynamic_cast oferece verificação de segurança de tipos, sendo uma conversão baseada em consulta de capacidade (Capability Query); por isso, para conversões entre tipos polimórficos, é mais recomendado usar dynamic_cast.
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++那些事
- Constantes e modificadores com const em C++ | 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++那些事