Introdução
A transformação de tipos em C++ é uma operação que requer cautela. Conforme destacado em Effective C++, o sistema de tipos da linguagem foi concebido para prevenir erros de tipo, e as conversões explicitas subvertem essa proteção. Apesar dos riscos, elas são inevitáveis em cenários práticos de desenvolvimento.
Antes da padronização dos operadores de conversão modernos, utilizava-se a notação em estilo C:
(Tipo)valor
Tipo(valor)
Essas formas legadas apresentam desvantagens significativas: baixa visibilidade no código, ausência de verificação em tempo de compilação e comportamento pouco previsível. O C++ moderno oferece quatro operadores especializados que endereçam essas limitações:
static_castdynamic_castreinterpret_castconst_cast
Este artigo examina especificamente o const_cast, suas capacidades e situações apropriadas de emprego.
Fundaemntos do const_cast
A sintaxe const_cast<NovoTipo>(expressao) possui uma função exclusiva: a remoção da qualificação const ou volatile de um tipo. Nenhum outro operador de conversão C++ oferece essa possibilidade.
A partir do C++11, o const_cast admite:
- Conversão entre potneiros de múltiplos níveis para o mesmo tipo, independentemente das qualificações
cvem cada nível - Transformação de valores nulos entre diferentes categorias de ponteiros
Em termos práticos, o operador permite:
- Converter ponteiro para constante em ponteiro mutável, mantendo o endereço do objeto original
- Converter referência para constante em referência mutável, preservando a vinculação ao objeto
Categorias de valor de retorno
O resultado da operação depende da categoria do tipo alvo:
| Tipo alvo | Categoria retornada |
|---|---|
| Referência lvalue ou referência rvalue para função | lvalue |
| Referência rvalue para tipo objeto | xvalue |
| Demais casos | prvalue |
As categorias de valor em C++11 seguem uma taxonomia baseada em duas propriedades ortogonais: possuir identidade (endereço acessível) e ser movível. Isso resulta em:
- lvalue: identidade presente, não movível
- xvalue: identidade presente, movível
- prvalue: identidade ausente, movível
Restrições e comportamentos indefinidos
O uso do const_cast está sujeito a importantes limitações:
- Ponteiros para funções e ponteiros para membros de função estão isentos das restrições de qualificação
const - É possível obter referência ou ponteiro não-const para objeto declarado
const, ou não-volatilepara objetovolatile - A modificação efetiva de objeto
constatravés de caminho de acesso não-constconstitui comportamento indefinido
Exemplos práticos
Conversão para referência lvalue
int valor = 10;
const int& refConst = valor;
// Remoção da constância permite modificação
const_cast<int&>(refConst) = 20;
std::cout << "valor: " << valor; // Exibe: 20
Aqui, o resultado é um lvalue, permitindo atribuição.
Conversão para referência rvalue de função
void saudacao() { std::cout << "Olá\n"; }
void despedida() { std::cout << "Adeus\n"; }
int main() {
const std::reference_wrapper<void()> func = std::ref(saudacao);
// const_cast retorna lvalue, permitindo reatribuição
const_cast<std::reference_wrapper<void()>&&>(func) = despedida;
func(); // Executa despedida
}
Conversão para referência rvalue de objeto
class Entidade {
public:
int dado;
explicit Entidade(int v) : dado(v) {}
};
int main() {
const Entidade&& temporario = Entidade(5);
// const_cast produz xvalue; requer vinculação a nova referência
Entidade&& mutavel = const_cast<Entidade&&>(temporario);
mutavel.dado = 15;
std::cout << temporario.dado; // 15 (compartilham endereço)
}
Manipulação de ponteiro para membro
struct Buffer {
int capacidade;
Buffer() : capacidade(100) {}
void ajustar(int novaCap) const {
// this é ponteiro para const; const_cast permite modificação
const_cast<Buffer*>(this)->capacidade = novaCap;
}
};
int main() {
Buffer b;
b.ajustar(200);
// b.capacidade == 200 (válido: objeto não era const)
}
Tentativa inválida: modificação de objeto verdadeiramente const
const int imutavel = 42;
int* ptr = const_cast<int*>(&imutavel);
// *ptr = 0; // COMPORTAMENTO INDEFINIDO - não execute!
A variável foi declarada const; qualquer tentativa de modificação viola o contrato da linguagem.
Limitação sintática
const int fixo = 7;
// int copia = const_cast<int>(fixo); // ERRO: não se aplica a valores
O operador opera exclusivamente sobre ponteiros, referências e ponteiros para membros.