Ir para o conteúdo principal
HistóriaHistória da informáticaIniciante

C++: de C with Classes ao C++ moderno

De C with Classes aos padrões modernos, descubra como C++ conciliou abstração, programação genérica, compatibilidade e controlo do desempenho.

Publicado 10 de agosto de 2026Atualizado 15 de setembro de 2026Leitura : 10 minPor Yann Bastien
C++: de C with Classes ao C++ moderno
Mostrar índice
  1. De C a C with Classes
  2. 1983: nasce o nome C++
  3. Orientada a objetos, mas nunca apenas a objetos
  4. Zero-overhead abstractions
  5. RAII: usar a duração de vida como ferramenta
  6. Templates e programação genérica
  7. 1998: um padrão ISO
  8. C++11 e a era do C++ moderno
  9. Um ritmo de evolução mais regular
  10. Porque continua C++ tão complexo?
  11. C++, Java e compromissos diferentes
  12. Onde C++ continua importante
  13. O que revela a história de C++
  14. Cronologia
  15. Perguntas frequentes
  16. C++ é simplesmente uma versão orientada a objetos de C?
  17. Porque mantém C++ compatibilidade com C?
  18. O que significa «C++ moderno»?
  19. Porque não exige C++ um garbage collector?
  20. C++ continua relevante perante Rust e linguagens mais recentes?
  21. Porque não elimina C++ mais funcionalidades antigas à medida que evolui?

C++ ocupa um lugar singular na história das linguagens de programação. Desde o final da década de 1970, persegue um objetivo difícil: permitir abstrações poderosas sem abdicar do controlo direto dos recursos nem de um desempenho próximo da máquina.

Esta tensão entre abstração e controlo explica grande parte da sua evolução. C++ incorporou classes, programação genérica, uma extensa biblioteca padrão, técnicas funcionais e concorrência, mantendo ao mesmo tempo uma forte continuidade com C e com décadas de software existente.

O resultado é uma linguagem simultaneamente poderosa e complexa. A sua história mostra que essa complexidade não resulta apenas de uma acumulação acidental: muitas vezes reflete compromissos deliberados entre compatibilidade, desempenho e capacidade para servir tipos de software muito diferentes.

De C a C with Classes

No início da década de 1970, C afirmou-se nos Bell Labs como uma ferramenta particularmente eficaz para desenvolver Unix. A linguagem de Dennis Ritchie combinava portabilidade relativa, acesso direto à memória e um modelo de execução simples, tornando-se rapidamente uma referência da programação de sistemas.

À medida que o software crescia, surgia outra questão: como estruturar sistemas de grande dimensão sem perder as qualidades que tornavam C tão útil?

No final dos anos 1970, Bjarne Stroustrup utilizou Simula durante o seu trabalho em Cambridge. Valorizava as suas classes e mecanismos de abstração, mas o desempenho disponível no seu ambiente não respondia a todas as necessidades.

Quando entrou nos Bell Labs em 1979, começou a procurar uma combinação: preservar a eficiência e o ecossistema de C e acrescentar abstrações inspiradas, entre outras fontes, em Simula. O projeto recebeu o nome C with Classes.

As primeiras versões ofereciam classes, construtores e destruidores, controlo de acesso e herança. Stroustrup desenvolveu também Cfront, que traduzia a nova linguagem para C antes de um compilador C existente produzir o programa final. Esta estratégia pragmática facilitou a experimentação e a utilização em sistemas que já dispunham de ferramentas C.

1983: nasce o nome C++

Em 1983, C with Classes passou a chamar-se C++, nome proposto por Rick Mascitti. Em C, ++ incrementa um valor, pelo que o nome sugere um C «incrementado» em vez de uma substituição completa.

A linguagem foi acrescentando ou reforçando funções virtuais, sobrecarga de funções e operadores, referências, constantes e verificação de tipos mais rigorosa. Em 1985, a primeira edição de The C++ Programming Language acompanhou a sua difusão para além do ambiente experimental dos Bell Labs.

A continuidade com C tinha grande valor estratégico. Os programadores podiam reutilizar conhecimentos, bibliotecas e ferramentas. Mas criou também um encargo duradouro: C++ teria de conciliar os seus novos mecanismos com uma herança concebida antes da própria linguagem.

Orientada a objetos, mas nunca apenas a objetos

A programação orientada a objetos cresceu rapidamente nas décadas de 1980 e 1990. C++ ajudou a popularizar classes, encapsulamento, herança e funções virtuais para polimorfismo dinâmico.

No entanto, descrever C++ simplesmente como «C com objetos» tornou-se rapidamente insuficiente. A linguagem nunca impôs um único modelo. Funções livres, tipos por valor, classes, herança, programação genérica e acesso direto aos recursos podem coexistir no mesmo programa.

Esta abordagem multiparadigma distingue C++ de linguagens construídas em torno de um modelo de objetos mais uniforme.

Zero-overhead abstractions

Uma expressão resume grande parte da filosofia de C++: zero-overhead abstractions.

As funcionalidades que não são utilizadas não devem impor um custo; as abstrações utilizadas não devem ser significativamente menos eficientes do que uma implementação manual equivalente bem escrita.

Isto não significa que todas as abstrações de C++ sejam literalmente gratuitas. Significa que a linguagem procura permitir conceitos de alto nível sem impor universalmente uma máquina virtual, um garbage collector ou um modelo de runtime mais pesado.

Esta ambição explica tanto a eficiência de C++ como parte da sua dificuldade. Manter representação, duração de vida e custos precisamente controláveis exige mais conceitos do que em ambientes que optam por esconder essas decisões.

RAII: usar a duração de vida como ferramenta

Construtores e destruidores conduziram a um dos idiomas mais característicos de C++: RAII, Resource Acquisition Is Initialization.

Um recurso fica associado à duração de vida de um objeto. O construtor pode adquiri-lo e o destruidor libertá-lo automaticamente quando o objeto sai do seu âmbito. Pode tratar-se de memória, mas também de um ficheiro, um bloqueio, uma ligação ou um identificador do sistema operativo.

RAII transforma a destruição determinística de objetos num mecanismo geral de gestão de recursos. Continua central no C++ moderno e ajuda a explicar por que razão as boas práticas atuais evitam frequentemente chamadas manuais dispersas a new e delete.

Templates e programação genérica

No final dos anos 1980 e início dos anos 1990, os templates deram outra dimensão a C++. Funções e tipos passaram a poder ser parametrizados por outros tipos, permitindo exprimir algoritmos e estruturas de dados de forma genérica.

Foi uma mudança decisiva. C++ deixou de ser apenas C com orientação a objetos e tornou-se também um dos grandes ambientes da programação genérica.

O trabalho de Alexander Stepanov e dos seus colaboradores conduziu à Standard Template Library, ou STL. A sua ideia fundamental consiste em separar os contentores dos algoritmos que operam sobre eles através de interfaces genéricas, em especial iteradores.

Contentores como vector e map podem assim utilizar algoritmos padrão de ordenação, pesquisa e transformação sem exigir uma versão específica de cada algoritmo para cada contentor.

A STL demonstrou que genericidade, reutilização, abstração e desempenho podem coexistir. Tornou-se uma parte fundamental da biblioteca padrão e alterou a forma idiomática de escrever C++.

1998: um padrão ISO

Com a multiplicação dos compiladores aumentou o risco de dialetos incompatíveis. A normalização internacional tornou-se indispensável.

Em 1998, C++ recebeu o primeiro padrão ISO completo. C++98 formalizou a linguagem e integrou a STL na biblioteca padrão. C++03 surgiu depois como revisão corretiva.

A normalização alterou também a governação. A evolução passou a decorrer através de um comité internacional, propostas, implementações e compromissos entre muitos participantes.

A estabilidade favoreceu a adoção industrial, mas nos anos 2000 consolidou-se também a reputação de C++ como linguagem difícil. Gestão manual da memória, ponteiros inválidos, fugas, sintaxe intrincada e diagnósticos de templates difíceis de ler eram críticas recorrentes.

C++11 e a era do C++ moderno

A grande viragem seguinte chegou em 2011. C++11 foi suficientemente importante para se falar habitualmente numa era de C++ moderno.

Entre as principais novidades encontram-se:

  • lambdas;
  • inferência de tipos com auto;
  • nullptr;
  • ciclos for baseados em intervalos;
  • smart pointers padrão;
  • rvalue references e move semantics;
  • constexpr;
  • variadic templates;
  • melhor suporte para concorrência.

Estas funcionalidades fizeram mais do que encurtar código: alteraram as práticas recomendadas.

A move semantics, por exemplo, permite transferir os recursos de um objeto que deixou de precisar deles em vez de os copiar. Smart pointers como std::unique_ptr e std::shared_ptr, combinados com RAII, tornam mais explícitas a propriedade e a duração de vida dos objetos.

O C++ moderno procura assim depender menos da gestão manual de cada recurso e mais de abstrações cujos custos e duração de vida continuam previsíveis.

Um ritmo de evolução mais regular

Depois de C++11, a linguagem adotou um ciclo de normalização de aproximadamente três anos.

C++14 aperfeiçoou muitos elementos de C++11. C++17 acrescentou ferramentas como std::optional, std::variant, std::filesystem e novas melhorias na programação genérica.

C++20 representou outro grande marco com concepts, ranges, coroutines e modules. Os concepts tornam mais explícitas as restrições sobre parâmetros genéricos; os ranges tornam muitas operações sobre sequências mais componíveis; as coroutines fornecem suporte da linguagem a determinados modelos assíncronos; os modules procuram, entre outros objetivos, melhorar a organização e a compilação relativamente ao modelo histórico de ficheiros de cabeçalho.

C++23 continuou esta evolução com novas melhorias na linguagem e na biblioteca. A estratégia geral mantém-se: modernizar C++ sem impor uma rutura brusca com a sua enorme base instalada.

Porque continua C++ tão complexo?

Várias causas reforçam-se mutuamente.

C++ preserva uma compatibilidade histórica considerável, suporta vários paradigmas e expõe detalhes de representação e duração de vida que outros ambientes escondem. Além disso, tem de funcionar tanto em aplicações comuns como em sistemas onde alguns bytes, alguns microssegundos ou a ausência de um runtime obrigatório fazem realmente diferença.

Esta liberdade significa também que existem frequentemente várias formas de resolver o mesmo problema. C++ antigo, C++ moderno e código escrito num estilo próximo de C podem coexistir na mesma base de código.

Bibliotecas e orientações modernas procuram, por isso, reduzir a parte mais perigosa desse espaço: contentores padrão em vez de arrays manuais quando adequado, RAII para recursos, smart pointers quando existe propriedade dinâmica e algoritmos e tipos expressivos em vez de gestão manual repetitiva.

C++, Java e compromissos diferentes

O aparecimento de Java nos anos 1990 ilustra outra resposta a alguns problemas encontrados pelos programadores C++. Java manteve uma sintaxe familiar, mas apoiou-se numa máquina virtual e em garbage collection e restringiu vários mecanismos de baixo nível.

C++ favorece o controlo direto da representação, a gestão determinística dos recursos e a ausência de custos obrigatórios por funcionalidades não utilizadas. Java aceita um ambiente de execução mais estruturado em troca de um modelo mais uniforme.

Nenhum destes compromissos é universalmente superior: as duas linguagens respondem, em parte, a restrições diferentes.

Onde C++ continua importante

Apesar de muitos concorrentes mais recentes, C++ continua importante quando contam o desempenho, a latência, o controlo da memória, a portabilidade nativa ou o acesso ao hardware.

É amplamente utilizado em motores de jogos, navegadores, bases de dados, ferramentas criativas, computação científica, sistemas embebidos, infraestruturas de baixa latência e bibliotecas utilizadas por outras linguagens.

A sua idade é simultaneamente uma limitação e uma vantagem. Décadas de compiladores, bibliotecas, conhecimento especializado e software industrial formam um ecossistema que não pode ser substituído de uma só vez.

Linguagens mais recentes, em especial Rust, oferecem compromissos diferentes em torno da segurança da memória e da programação de sistemas. Podem competir com C++ em algumas áreas sem tornar obsoleta a sua enorme base de software.

O que revela a história de C++

C++ não passou de forma linear de uma linguagem antiga para outra completamente redesenhada. Cresceu por camadas: C with Classes, orientação a objetos, templates, STL, normalização, C++ moderno e, depois, um ciclo regular de novos padrões.

Algumas destas camadas contribuem para a complexidade. Outras fornecem precisamente as abstrações que permitem substituir práticas antigas por código mais seguro e expressivo sem perder as propriedades que tornaram C++ valioso.

A sua longevidade assenta, portanto, num equilíbrio pouco habitual: mudar o suficiente para continuar relevante, mas não tanto que rompa com o mundo que já depende da linguagem.

Cronologia

  • 1979: Bjarne Stroustrup inicia C with Classes nos Bell Labs.
  • 1983: a linguagem recebe o nome C++.
  • 1985: primeira edição de The C++ Programming Language e primeira difusão comercial.
  • Final dos anos 80–anos 90: desenvolvimento dos templates e da programação genérica.
  • Anos 90: a STL de Alexander Stepanov entra no processo de normalização.
  • 1998: primeiro padrão ISO, C++98.
  • 2003: revisão corretiva C++03.
  • 2011: C++11 abre a era do C++ moderno.
  • 2014: C++14.
  • 2017: C++17.
  • 2020: C++20 introduz, entre outras funcionalidades, concepts, ranges, coroutines e modules.
  • 2023: C++23 prossegue a evolução da linguagem e da biblioteca.
  • Hoje: C++ continua a evoluir através da normalização ISO e permanece amplamente utilizado em software sensível ao desempenho.

Perguntas frequentes

C++ é simplesmente uma versão orientada a objetos de C?

Não. A orientação a objetos foi central na história inicial, mas templates, STL, RAII e programação genérica tornaram-se igualmente importantes. C++ é uma linguagem multiparadigma.

Porque mantém C++ compatibilidade com C?

C++ foi concebido como uma evolução pragmática de C e beneficiou do seu ecossistema. Essa continuidade facilitou a adoção. A compatibilidade não é, contudo, absoluta: código C válido não é necessariamente código C++ válido.

O que significa «C++ moderno»?

A expressão refere-se geralmente a práticas e funcionalidades associadas a C++11 e versões posteriores: utilização sistemática de RAII, contentores e algoritmos padrão, smart pointers, move semantics, lambdas e outras ferramentas para código mais expressivo e seguro.

Porque não exige C++ um garbage collector?

A linguagem favorece o controlo determinístico dos recursos e evita impor a todos os programas o custo de um coletor ou de um runtime específico. RAII, contentores e smart pointers automatizam grande parte da gestão sem garbage collection obrigatória.

C++ continua relevante perante Rust e linguagens mais recentes?

Sim. O seu ecossistema, desempenho, portabilidade nativa e enorme base de software existente continuam a ser vantagens importantes. Rust oferece garantias diferentes de segurança da memória e é uma alternativa relevante para alguns novos projetos de sistemas, mas as duas linguagens coexistem em muitos domínios.

Porque não elimina C++ mais funcionalidades antigas à medida que evolui?

Porque a compatibilidade com décadas de software tem grande valor para o ecossistema. O comité prefere frequentemente acrescentar mecanismos melhores e alterar as práticas recomendadas em vez de tornar abruptamente incompatíveis grandes quantidades de código existente.

Este artigo foi útil?

Fontes e referências

  1. 1.Bjarne Stroustrup - A History of C++
  2. 2.Bjarne Stroustrup - The Design and Evolution of C++
  3. 3.ISO C++ Foundation - The Standard

Coleção

Linguagens de programação

9 / 26

  1. 01Grace Hopper: dos primeiros compiladores ao COBOL
  2. 02John Backus: FORTRAN, a notação BNF e a recusa do código de máquina
  3. 03Dennis Ritchie: a linguagem C no coração do Unix
  4. 04FORTRAN: provar que um compilador pode competir com assembly
  5. 05A linguagem C: tornar os sistemas portáteis sem esconder a máquina
  6. 06Niklaus Wirth: de Pascal a Oberon, conceber pela simplicidade
  7. 07Bjarne Stroustrup: conceber C++ sem abdicar do desempenho
  8. 08Pascal: aprender a programar tornando a estrutura visível
  9. 09C++: de C with Classes ao C++ moderno
  10. 10Programação orientada a objetos: objetos, mensagens e abstrações reutilizáveis
  11. 11Guido van Rossum: criar Python para tornar o código legível
  12. 12Brendan Eich: JavaScript, do protótipo da Netscape ao padrão da Web
  13. 13James Gosling: o engenheiro na origem de Java
  14. 14Python: legibilidade, baterias incluídas e um ecossistema global
  15. 15Java: escrever uma vez, executar em qualquer lugar
  16. 16JavaScript: a linguagem que tornou a Web interativa
  17. 17Ken Thompson: de Unix a Go, a simplicidade como método
  18. 18John McCarthy: Lisp e a ideia de programar com símbolos
  19. 19Alan Kay: Smalltalk e o computador como meio pessoal
  20. 20Barbara Liskov: a abstração que tornou o software modular
  21. 21Robin Milner: ML, prova assistida e linguagens da interação
  22. 22Brian Kernighan: AWK, Unix e a arte de explicar código
  23. 23Anders Hejlsberg: de Turbo Pascal a C# e TypeScript
  24. 24Larry Wall: Perl, a linguagem que ligou as ferramentas da Internet
  25. 25Yukihiro Matsumoto: Ruby e a felicidade do programador
  26. 26Rasmus Lerdorf: PHP e a democratização da Web dinâmica
BiografiaHistória da informáticaIniciante

James Gosling: o engenheiro na origem de Java

Como James Gosling e a equipa Green da Sun conceberam Java: de Oak às máquinas virtuais e à promessa de portabilidade.

17 de agosto de 20265 min