O Mapa da Jornada: de C a C++ em 52 Passos

O Mapa da Jornada: de C a C++ em 52 Passos

Quem vem do C chega com vantagem e com risco: a fundação está pronta, mas o maior obstáculo não é aprender o novo — é desaprender hábito, porque C++ não é "C com classes". Este artigo não ensina sintaxe nenhuma. Ele desenha o mapa das nove fases, para que cada conceito difícil chegue com lugar reservado.
Linguagem C++

9 min de leitura

Você chega aqui com uma vantagem enorme e um risco igualmente grande. A vantagem é que você já sabe C: entende ponteiros, sabe o que é a pilha e o heap, já fez malloc/free na mão, já lutou com segmentation faults e ganhou. Nada disso será jogado fora — pelo contrário, é a fundação sobre a qual vamos construir. O risco é acreditar que C++ é "C com classes", uma casquinha de açúcar sintático por cima do que você já conhece. Não é. C++ é uma linguagem com uma filosofia própria, às vezes oposta à do C, e o maior obstáculo do programador C experiente não é aprender o novo — é desaprender certos hábitos. Este primeiro artigo não ensina sintaxe nenhuma: ele é o mapa. Vou te mostrar aonde vamos chegar em cada uma das nove fases, para que, quando um conceito difícil aparecer, você já saiba qual peça do quebra-cabeça ele preenche.

A ideia central que atravessa todo o curso cabe em uma frase: em C, você gerencia recursos; em C++, os recursos se gerenciam sozinhos. Toda vez que em C você escreveria um free, um fclose, um pthread_mutex_unlock, o C++ moderno oferece um jeito de deixar isso acontecer automaticamente, no momento certo, mesmo que o código exploda com um erro no meio do caminho. Esse mecanismo se chama RAII, e ele é o coração pulsante da linguagem. Se você sair deste curso entendendo profundamente uma única coisa, que seja RAII — guarde este nome, porque a Fase 2 inteira é dedicada a ele e praticamente tudo depois se apoia nele.

Como vamos trabalhar

A ferramenta é o compilador g++ (ou clang++, se preferir). Ao longo da série usaremos C++ moderno — predominantemente C++17 e C++20 — e eu sempre direi quando um recurso for específico de uma versão, para você não se surpreender ao compilar num ambiente mais antigo. A linha de compilação padrão que usaremos, com os avisos ligados, é esta:

# -std=c++20  → escolhe o padrão da linguagem (C++20)
# -Wall -Wextra → liga a maioria dos avisos úteis do compilador
# -o programa → nome do executável de saída
g++ -std=c++20 -Wall -Wextra programa.cpp -o programa
./programa

Repare que a extensão é .cpp, não .c, e o compilador é g++, não gcc. Isso já basta para o "Olá, mundo" mais famoso do C++ mostrar sua cara — e a diferença em relação ao printf do C já conta uma história:

#include <iostream>   // entrada e saída por streams, o equivalente ao <stdio.h>

int main() {          // em C++, main() sem parâmetros dispensa o 'void'
    // std::cout é o fluxo de saída; << "empurra" dados para dentro dele.
    // std::endl imprime uma quebra de linha e descarrega o buffer.
    std::cout << "Olá, C++!" << std::endl;
    return 0;
}

Onde em C você diria printf("Olá, C++!\n"), aqui usamos std::cout <<. Não há string de formato, não há %d nem %s, não há risco de passar o tipo errado e corromper a pilha. O operador << sabe, em tempo de compilação, o tipo de cada coisa que você imprime. Essa é a primeira pista da filosofia do C++: empurrar o máximo de segurança para o momento da compilação. Não se preocupe com o std:: na frente de tudo agora — namespaces são assunto do artigo A Filosofia por Trás do C++ e a Saída Elegante do printf.

As nove fases da jornada

A série tem 52 artigos organizados em nove fases. Cada fase fecha com um balanço do que você conquistou.

Na Fase 1 — O que muda ao sair do C, atacamos justamente os hábitos de C que precisam de ajuste: streams no lugar de printf/scanf, namespaces, referências como alternativa mais segura aos ponteiros, const-correctness levada a sério, sobrecarga de funções, a classe std::string no lugar do char* cru, nullptr no lugar de NULL, e uma primeira olhada em auto. Ao fim dela, você escreve C++ que já não parece C disfarçado.

Na Fase 2 — RAII e gerenciamento de recursos, chegamos ao coração da linguagem: construtores, destrutores, e a descoberta de por que o par malloc/free praticamente desaparece. Você conhecerá os ponteiros inteligentes (unique_ptr, shared_ptr, weak_ptr) e entenderá por que new/delete cru se torna raro. Como consequência natural, veremos move semantics — mover recursos em vez de copiá-los. Ao fim, você não vaza mais memória por acidente, porque o próprio design impede o vazamento.

Na Fase 3 — Classes e orientação a objetos, construímos tipos de verdade: encapsulamento, herança, polimorfismo com funções virtuais, classes abstratas e sobrecarga de operadores. Mas seremos honestos sobre quando OO ajuda e quando atrapalha — nem tudo precisa virar uma hierarquia de classes.

Na Fase 4 — A STL, você ganha as estruturas de dados que em C você implementava à mão: vector, map, set, unordered_map, tudo unificado pelo conceito de iterador, e a biblioteca <algorithm> (sort, find, transform, accumulate). Ao fim, você para de reinventar listas ligadas e tabelas hash.

Na Fase 5 — Genericidade, entramos nos templates: funções e classes que funcionam com qualquer tipo, especialização, uma introdução a concepts (C++20), lambdas e std::function. É a fase em que você escreve código uma vez e ele serve para tudo.

Na Fase 6 — Tratamento de erros e C++ moderno, vemos exceções e sua relação íntima com RAII, além dos tipos que modelam ausência e alternativas: std::optional, std::variant, std::expected, structured bindings e a dedução de tipos com auto em profundidade.

Na Fase 7 — Concorrência, comparamos com os pthreads do C e usamos as ferramentas nativas: std::thread, std::async, std::mutex, std::atomic, std::condition_variable, e aprendemos a evitar data races e deadlocks.

Na Fase 8 — Ferramentas, qualidade e boas práticas, montamos projetos de verdade com CMake, ligamos sanitizers e clang-tidy, seguimos as C++ Core Guidelines e escrevemos testes com Catch2 ou GoogleTest.

E a Fase 9 — Fechamento é o projeto capstone: uma aplicação real, do zero, que integra tudo — RAII, ponteiros inteligentes, classes, STL, templates, exceções e testes —, seguida de uma retrospectiva da jornada inteira.

Um mapa não substitui o caminho, mas evita a sensação de estar perdido no meio dele — e é isso que este primeiro artigo compra: quando o RAII aparecer, você já saberá que fase ele fecha e que problema ele resolve. Vale voltar aqui sempre que um conceito parecer solto, porque quase nenhum deles é: a maior parte do C++ que vem adiante existe para resolver algo que o C deixava por sua conta.

Fontes e leituras recomendadas

  • Bjarne Stroustrup, A Tour of C++ (3ª ed., 2022): escrito pelo criador da linguagem, é o panorama moderno mais conciso e a leitura de cabeceira ideal para acompanhar esta série.
  • Bjarne Stroustrup, The C++ Programming Language (4ª ed.): a referência completa e definitiva, para consulta aprofundada quando um tema pedir mais.
  • cppreference.com: a documentação online mais confiável e precisa da biblioteca padrão; será citada em quase todos os artigos. Comece por cppreference.com/w/cpp/language/history.
  • ISO C++ Core Guidelines (isocpp.github.io/CppCoreGuidelines): o guia de boas práticas mantido por Stroustrup e Herb Sutter; usaremos várias de suas regras ao longo do curso.
  • Documentação do GCC (gcc.gnu.org/onlinedocs): referência das flags de compilação que adotaremos, incluindo -std e os avisos.

Exercícios

Exercício 1

Verifique qual versão do g++ você tem instalada e confirme que ela suporta C++20. (Dica: existe uma flag para o compilador imprimir a própria versão.)

Ver resposta

✓ Resposta: O comando é g++ --version. A saída mostra a versão (por exemplo, g++ (GCC) 13.2.0). Como regra prática, GCC 10 ou superior dá bom suporte a C++20, e GCC 11+ é ainda mais completo. Se a sua versão for antiga, atualize antes de seguir — o curso assume C++20 disponível.

Exercício 2

Salve o "Olá, C++!" deste artigo em um arquivo ola.cpp, compile-o com as flags recomendadas e execute-o.

Ver resposta

✓ Resposta: Basta colar o código do artigo em ola.cpp e rodar:

g++ -std=c++20 -Wall -Wextra ola.cpp -o ola
./ola
# Saída: Olá, C++!

Se não compilar, o erro mais comum é ter usado gcc (compilador C) em vez de g++.

Exercício 3

Modifique o programa para imprimir duas linhas: seu nome numa linha e o ano atual em outra, usando um único std::cout encadeado com dois << e uma quebra de linha no meio.

Ver resposta

✓ Resposta: Uma solução encadeia tudo em um só std::cout:

#include <iostream>

int main() {
    // Um único statement com vários operadores <<.
    // O '\n' quebra a linha entre o nome e o ano.
    std::cout << "Maria Silva" << '\n' << 2026 << std::endl;
    return 0;
}

Repare que '\n' (aspas simples) é um único caractere, mais barato que std::endl, que além de quebrar a linha também descarrega o buffer. Voltaremos a essa distinção adiante.

Exercício 4

Compile o mesmo programa uma vez com -std=c++20 e outra com -std=c++11. Ele funciona nos dois casos? Reflita sobre por que um "Olá, mundo" não revela diferença entre os padrões.

Ver resposta

✓ Resposta: Sim, funciona nos dois padrões. Um "Olá, mundo" usa apenas recursos presentes desde os primeiros C++, então nenhuma diferença aparece. As diferenças entre C++11, C++17 e C++20 só surgem quando você usa recursos específicos de cada versão — e é por isso que este curso vai introduzi-los aos poucos, sempre dizendo a partir de qual padrão cada um existe.

Exercício 5

Sem escrever código: para cada uma das nove fases, escreva em uma frase qual hábito de C você espera que ela substitua ou aprimore. (Este é um exercício de mapa mental; compare sua resposta com o gabarito.)

Ver resposta

✓ Resposta: Não há uma resposta única, mas um bom mapa mental seria: Fase 1 substitui printf/scanf e char* por streams e std::string; Fase 2 substitui malloc/free por RAII e ponteiros inteligentes; Fase 3 substitui structs com funções soltas por classes com comportamento encapsulado; Fase 4 substitui suas implementações manuais de listas e tabelas hash pela STL; Fase 5 substitui macros e duplicação de código por templates; Fase 6 substitui códigos de erro por exceções e tipos como std::optional; Fase 7 substitui pthreads por std::thread e companhia; Fase 8 substitui Makefiles artesanais e depuração no escuro por CMake, sanitizers e testes; Fase 9 junta tudo num projeto real. Se a sua lista bateu em espírito com esta, você já entendeu para onde vamos.

Comentários

Mais em Linguagem C++

Extensão — Além do SQLite: PostgreSQL, MySQL e MongoDB
Extensão — Além do SQLite: PostgreSQL, MySQL e MongoDB

Trocar o SQLite por PostgreSQL, MySQL ou MongoDB muda a API e quase nada do…

Entidades de Verdade — Componentes e o Padrão ECS
Entidades de Verdade — Componentes e o Padrão ECS

Modelar objetos de jogo por herança quebra no primeiro inimigo que também voa…

Percorrendo com Elegância — o Range-Based for a Fundo
Percorrendo com Elegância — o Range-Based for a Fundo

A sintaxe curta esconde uma decisão que custa caro se for tomada por descuido…