static_cast vs dynamic_cast vs C-style cast: como não quebrar o código

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que a conversão de tipos em C++ é um campo minado

\n\n

Você já escreveu algo como (int)someFloat e esperou que tudo ficasse bem? Ou talvez já tenha se deparado com uma situação em que o programa compila, mas falha em tempo de execução com um erro misterioso? Bem-vindo ao mundo da conversão de tipos em C++ — um lugar onde até mesmo desenvolvedores experientes perdem horas depurando.

\n\n

A pergunta "Regular cast vs. static_cast vs. dynamic_cast" no Stack Overflow acumulou dezenas de milhares de visualizações. E isso não é por acaso. Cada tipo de conversão é uma ferramenta com seu próprio propósito, e usar a ferramenta errada pode levar a comportamento indefinido, vazamentos de memória ou simplesmente a um código que não funciona.

\n\n

Neste artigo, analisaremos três formas principais de conversão de tipos em C++, mostraremos os erros mais comuns e daremos recomendações claras sobre como evitá-los. Ao final, você saberá exatamente qual cast usar em cada situação específica.

\n\n

1. Regular cast (C-style cast) — herança do passado

\n\n

O bom e velho C-style cast é a forma mais simples, mas ao mesmo tempo a mais perigosa de conversão. Ele se parece com isto: (NewType)expression. Em C++, ele é considerado "regular", mas seu comportamento pode surpreender bastante.

\n\n

Como funciona?

\n

O compilador C++ tenta interpretar o C-style cast como uma sequência de static_cast, const_cast e reinterpret_cast. Ele escolhe a primeira combinação adequada. O problema é que você nunca sabe qual cast exatamente será aplicado no final.

\n\n

Exemplo de erro: alteração acidental de constância

\n
const int value = 42;\nint* ptr = (int*)&value;  // C-style cast remove const\n*ptr = 100;               // Comportamento indefinido!\ncout << value;           // Pode exibir 42, 100 ou qualquer coisa
\n\n

Este código compila sem erros, mas leva a um comportamento indefinido. const_cast aqui seria mais honesto — pelo menos mostraria sua intenção.

\n\n

Quando o C-style cast ainda é aceitável?

\n
    \n
  • Nunca em C++ moderno (C++11 e posteriores).
  • \n
  • Apenas para conversões numéricas muito simples, onde o risco é mínimo (por exemplo, (float)intValue), mas mesmo assim é melhor usar static_cast.
  • \n
\n\n

Conclusão: esqueça o C-style cast. Ele torna o código ilegível e inseguro. Compiladores modernos podem até emitir avisos para tais construções.

\n\n

2. static_cast — o soldado universal

\n\n

static_cast é o tipo de conversão mais usado em C++. Ele realiza a verificação em tempo de compilação e é adequado para a maioria das situações em que a conversão de tipos é logicamente correta.

\n\n

Quando usar static_cast?

\n
    \n
  • Conversão de tipos numéricos: double → int, int → float.
  • \n
  • Upcast (conversão de ponteiro de classe derivada para ponteiro de classe base).
  • \n
  • Conversão explícita de void* de volta para um tipo específico.
  • \n
  • Chamada de construtores com um argumento (mas é melhor usar explicit).
  • \n
\n\n

Exemplo: upcast correto

\n
class Base { public: virtual void speak() { cout << "Base"; } };\nclass Derived : public Base { public: void speak() override { cout << "Derived"; } };\n\nDerived d;\nBase* b = static_cast<Base*>(&d);  // upcast — seguro\nb->speak();  // Exibirá "Derived" graças à função virtual
\n\n

Erro principal #1: Slicing ao passar por valor

\n

Um dos erros mais traiçoeiros é o slicing (fatiamento de objeto). Ele ocorre quando você converte um objeto de classe derivada para a classe base por valor, e não por referência ou ponteiro

Blogs

Book Recommendations