Ir al contenido principal
Bethemesh
HistoriaHistoria de la informáticaPrincipiante

C++: de C with Classes al C++ moderno

De C with Classes a los estándares modernos, descubre cómo C++ ha conciliado abstracción, programación genérica, compatibilidad y control del rendimiento.

Publicado el 10 de agosto de 2026Actualizado el 15 de septiembre de 2026Lectura : 11 minPor Yann Bastien
C++: de C with Classes al C++ moderno
Mostrar el índice
  1. De C a C with Classes
  2. 1983: nace el nombre C++
  3. Orientado a objetos, pero nunca solo orientado a objetos
  4. La idea central: abstracciones sin sobrecoste
  5. RAII: convertir la duración de vida en una herramienta
  6. Templates y programación genérica
  7. 1998: un estándar ISO
  8. C++11 y la era del C++ moderno
  9. Un ritmo de evolución más regular
  10. ¿Por qué C++ sigue siendo tan complejo?
  11. C++, Java y distintos compromisos de diseño
  12. Dónde sigue siendo importante C++
  13. Lo que revela la historia de C++
  14. Cronología
  15. Preguntas frecuentes
  16. ¿C++ es simplemente una versión orientada a objetos de C?
  17. ¿Por qué C++ mantiene compatibilidad con C?
  18. ¿Qué significa «C++ moderno»?
  19. ¿Por qué C++ no exige un recolector de basura?
  20. ¿Sigue siendo relevante C++ frente a Rust y lenguajes más recientes?
  21. ¿Por qué C++ no elimina más funciones antiguas al evolucionar?

C++ ocupa un lugar singular en la historia de los lenguajes de programación. Desde finales de los años setenta persigue un objetivo difícil: ofrecer abstracciones potentes sin renunciar al control directo de los recursos ni a un rendimiento cercano a la máquina.

Esa tensión entre abstracción y control explica gran parte de su evolución. C++ ha incorporado clases, programación genérica, una amplia biblioteca estándar, técnicas funcionales y concurrencia, manteniendo al mismo tiempo una fuerte continuidad con C y con décadas de software existente.

El resultado es un lenguaje tan potente como complejo. Su historia muestra que esa complejidad no es únicamente una acumulación accidental: a menudo refleja decisiones deliberadas sobre compatibilidad, rendimiento y capacidad para servir a tipos de software muy diferentes.

De C a C with Classes

A comienzos de los años setenta, C se convirtió en Bell Labs en una herramienta especialmente eficaz para desarrollar Unix. El lenguaje de Dennis Ritchie combinaba portabilidad relativa, acceso directo a la memoria y un modelo de ejecución sencillo, y pronto se convirtió en una referencia de la programación de sistemas.

A medida que el software crecía surgía otra pregunta: ¿cómo estructurar sistemas grandes sin perder las cualidades que hacían útil a C? Nuestro artículo sobre la historia de C desarrolla ese contexto.

A finales de los setenta, Bjarne Stroustrup utilizó Simula durante su trabajo en Cambridge. Valoraba sus clases y mecanismos de abstracción, pero el rendimiento disponible en su entorno no respondía a todas sus necesidades.

Al incorporarse a Bell Labs en 1979 empezó a buscar una combinación: conservar la eficiencia y el ecosistema de C y añadir abstracciones inspiradas, entre otras fuentes, en Simula. El proyecto recibió el nombre C with Classes.

Las primeras versiones ofrecían clases, constructores y destructores, control de acceso y herencia. Stroustrup desarrolló además Cfront, que traducía el nuevo lenguaje a C antes de que un compilador C existente generara el programa final. Esta estrategia pragmática facilitó la experimentación y el despliegue en sistemas que ya disponían de herramientas para C.

1983: nace el nombre C++

En 1983, C with Classes pasó a llamarse C++, nombre propuesto por Rick Mascitti. En C, ++ incrementa un valor, de modo que el nombre sugiere un C «incrementado» más que un sustituto completo.

El lenguaje fue incorporando o reforzando funciones virtuales, sobrecarga de funciones y operadores, referencias, constantes y una comprobación de tipos más estricta. En 1985, la primera edición de The C++ Programming Language acompañó su difusión más allá del entorno experimental de Bell Labs.

La continuidad con C tenía un enorme valor estratégico. Los programadores podían reutilizar conocimientos, bibliotecas y herramientas. Pero también creó una carga duradera: C++ tendría que conciliar sus nuevos mecanismos con una herencia diseñada antes de que existiera el propio lenguaje.

Para profundizar en su creador, puede consultarse la biografía de Bjarne Stroustrup.

Orientado a objetos, pero nunca solo orientado a objetos

La programación orientada a objetos creció rápidamente durante las décadas de 1980 y 1990. C++ contribuyó a popularizar clases, encapsulación, herencia y funciones virtuales para el polimorfismo dinámico.

Sin embargo, describir C++ simplemente como «C con objetos» pronto dejó de ser exacto. El lenguaje nunca impuso un único modelo. Un programa puede combinar funciones libres, tipos por valor, clases, herencia, programación genérica y acceso directo a los recursos.

Este enfoque multiparadigma lo distingue de lenguajes construidos alrededor de un modelo de objetos más uniforme. Nuestra historia de la programación orientada a objetos sitúa esta evolución en el camino que va de Simula y Smalltalk a los lenguajes posteriores.

La idea central: abstracciones sin sobrecoste

Una expresión resume buena parte de la filosofía de C++: zero-overhead abstractions.

Tiene dos vertientes. Las funciones que no se utilizan no deberían imponer un coste, y las abstracciones que sí se utilizan no deberían ser significativamente menos eficientes que una implementación manual equivalente bien escrita.

Eso no significa que toda abstracción de C++ sea literalmente gratuita. Significa que el lenguaje pretende permitir ideas de alto nivel sin imponer universalmente una máquina virtual, un recolector de basura o un modelo de ejecución más pesado.

Esta ambición explica tanto la eficiencia de C++ como parte de su dificultad. Exponer con precisión la representación, la duración de vida y el coste requiere más conceptos que en entornos que deciden ocultarlos.

RAII: convertir la duración de vida en una herramienta

Los constructores y destructores dieron lugar a uno de los modismos más característicos de C++: RAII, Resource Acquisition Is Initialization.

Un recurso se vincula a la duración de vida de un objeto. Su constructor puede adquirirlo y su destructor liberarlo automáticamente cuando el objeto sale de su ámbito. El recurso puede ser memoria, pero también un archivo, un bloqueo, una conexión o un descriptor del sistema.

RAII convierte la destrucción determinista de objetos en un mecanismo general de gestión de recursos. Sigue siendo fundamental en el C++ moderno y ayuda a explicar por qué las buenas prácticas actuales evitan a menudo llamadas manuales dispersas a new y delete.

Templates y programación genérica

A finales de los ochenta y comienzos de los noventa, los templates dieron a C++ otra dimensión. Funciones y tipos podían parametrizarse con otros tipos, permitiendo expresar algoritmos y estructuras de datos de forma genérica.

Fue un cambio decisivo. C++ ya no se limitaba a añadir orientación a objetos a C: se convertía también en uno de los grandes espacios de la programación genérica.

Los trabajos de Alexander Stepanov y sus colaboradores desembocaron en la Standard Template Library, o STL. Su idea esencial era separar los contenedores de los algoritmos que operan sobre ellos mediante interfaces genéricas, especialmente iteradores.

Contenedores como vector o map pueden así utilizar algoritmos estándar de ordenación, búsqueda o transformación sin necesitar una versión específica de cada algoritmo para cada contenedor.

La STL demostró que genericidad, reutilización, abstracción y rendimiento podían convivir. Se convirtió en una parte fundamental de la biblioteca estándar y cambió la manera idiomática de escribir C++.

1998: un estándar ISO

A medida que proliferaban los compiladores aumentaba el riesgo de dialectos incompatibles. La normalización internacional se volvió imprescindible.

En 1998, C++ obtuvo su primera norma ISO completa. C++98 formalizó el lenguaje e incorporó la STL a la biblioteca estándar. C++03 llegó después como revisión correctiva.

La normalización cambió también la gobernanza. C++ dejó de ser únicamente el producto de su diseñador original o de un proveedor: su evolución pasó a depender de un comité internacional, propuestas, implementaciones y compromisos entre numerosos participantes.

La estabilidad favoreció la adopción industrial, pero durante los años 2000 también se consolidó la fama de C++ como lenguaje difícil. Gestión manual de memoria, punteros inválidos, fugas, sintaxis intrincada y diagnósticos intimidantes de templates eran críticas recurrentes.

C++11 y la era del C++ moderno

El siguiente gran punto de inflexión llegó en 2011. C++11 fue tan importante que se habla habitualmente de C++ moderno para distinguir las prácticas posteriores.

Entre sus principales incorporaciones se encuentran:

  • lambdas;
  • inferencia de tipos con auto;
  • nullptr;
  • bucles for sobre rangos;
  • smart pointers estándar;
  • rvalue references y move semantics;
  • constexpr;
  • variadic templates;
  • mejor soporte para concurrencia.

Estas funciones hicieron algo más que acortar el código: cambiaron las prácticas recomendadas.

La move semantics, por ejemplo, permite transferir los recursos de un objeto que ya no los necesita en vez de copiarlos. Los smart pointers como std::unique_ptr y std::shared_ptr, combinados con RAII, expresan con mayor claridad la propiedad y la duración de vida de los objetos.

El C++ moderno pretende así depender menos de la gestión manual de cada recurso y más de abstracciones cuyo coste y duración de vida sigan siendo previsibles.

Un ritmo de evolución más regular

Después de C++11, el lenguaje adoptó un ciclo de normalización de aproximadamente tres años.

C++14 refinó muchos elementos de C++11. C++17 añadió herramientas como std::optional, std::variant, std::filesystem y nuevas mejoras para la programación genérica.

C++20 fue otro gran hito con concepts, ranges, coroutines y modules. Los concepts permiten expresar mejor las restricciones sobre parámetros genéricos; los ranges hacen más componibles muchas operaciones sobre secuencias; las coroutines proporcionan soporte del lenguaje para determinados modelos asíncronos; los modules buscan, entre otras cosas, mejorar la organización y compilación frente al modelo histórico de archivos de cabecera.

C++23 continuó esta evolución con nuevas mejoras del lenguaje y la biblioteca. La estrategia general se mantiene: modernizar C++ sin obligar a romper con su enorme base instalada.

¿Por qué C++ sigue siendo tan complejo?

Varias causas se refuerzan mutuamente.

C++ conserva una amplia compatibilidad histórica. Admite varios paradigmas. Expone detalles de representación y duración de vida que otros entornos ocultan. Y debe funcionar tanto en aplicaciones convencionales como en sistemas donde unos pocos bytes, unos microsegundos o la ausencia de un runtime obligatorio importan de verdad.

Esta libertad implica además que suele haber varias maneras de resolver un mismo problema. C++ antiguo, C++ moderno y código escrito con un estilo cercano a C pueden convivir en una misma base de código.

Las bibliotecas y guías modernas intentan por ello reducir la parte peligrosa de ese espacio: contenedores estándar en lugar de arrays manuales cuando procede, RAII para los recursos, smart pointers cuando existe propiedad dinámica y algoritmos y tipos expresivos en lugar de repetir gestión manual.

C++, Java y distintos compromisos de diseño

La aparición de Java en los años noventa ilustra otra respuesta a algunos problemas de los desarrolladores C++. Java conservó una sintaxis familiar, pero se apoyó en una máquina virtual y un recolector de basura y limitó varios mecanismos de bajo nivel.

C++ favorece el control directo de la representación, la gestión determinista de recursos y la ausencia de costes obligatorios por funciones no utilizadas. Java acepta un entorno de ejecución más estructurado a cambio de un modelo más uniforme.

Ninguno de estos compromisos es universalmente superior: los lenguajes responden en parte a restricciones diferentes. La historia de Java permite comparar ambas trayectorias.

Dónde sigue siendo importante C++

A pesar de la aparición de muchos competidores, C++ sigue siendo importante cuando cuentan el rendimiento, la latencia, el control de memoria, la portabilidad nativa o el acceso al hardware.

Se utiliza ampliamente en motores de videojuegos, navegadores, bases de datos, herramientas creativas, cálculo científico, sistemas embebidos, infraestructuras de baja latencia y bibliotecas consumidas desde otros lenguajes.

Su edad es al mismo tiempo una limitación y una ventaja. Décadas de compiladores, bibliotecas, experiencia y software industrial forman un ecosistema que no puede sustituirse de una sola vez.

Lenguajes más recientes, especialmente Rust, ofrecen otros compromisos en torno a la seguridad de memoria y la programación de sistemas. Pueden competir con C++ en determinados ámbitos sin convertir en obsoleta su enorme base de software.

Lo que revela la historia de C++

C++ no pasó limpiamente de un lenguaje antiguo a otro completamente rediseñado. Creció por capas: C with Classes, orientación a objetos, templates, STL, normalización, C++ moderno y después un ciclo regular de nuevos estándares.

Algunas capas contribuyen a su complejidad. Otras proporcionan precisamente las abstracciones que permiten sustituir prácticas antiguas por código más seguro y expresivo sin perder las propiedades que hicieron valioso al lenguaje.

Su longevidad descansa así en un equilibrio poco habitual: cambiar lo suficiente para seguir siendo relevante, pero no tanto como para romper con el mundo que ya depende de él.

Cronología

  • 1979: Bjarne Stroustrup comienza C with Classes en Bell Labs.
  • 1983: el lenguaje recibe el nombre C++.
  • 1985: primera edición de The C++ Programming Language y primera difusión comercial.
  • Finales de los 80–años 90: desarrollo de los templates y la programación genérica.
  • Años 90: la STL de Alexander Stepanov entra en el proceso de normalización.
  • 1998: primera norma ISO, C++98.
  • 2003: revisión correctiva C++03.
  • 2011: C++11 abre la era del C++ moderno.
  • 2014: C++14.
  • 2017: C++17.
  • 2020: C++20 incorpora, entre otras funciones, concepts, ranges, coroutines y modules.
  • 2023: C++23 continúa la evolución del lenguaje y la biblioteca.
  • Hoy: C++ continúa evolucionando mediante la normalización ISO y sigue ampliamente presente en software sensible al rendimiento.

Preguntas frecuentes

¿C++ es simplemente una versión orientada a objetos de C?

No. La orientación a objetos fue central en sus primeros años, pero los templates, la STL, RAII y la programación genérica se volvieron igualmente importantes. C++ es un lenguaje multiparadigma.

¿Por qué C++ mantiene compatibilidad con C?

C++ nació como una evolución pragmática de C y se benefició de su ecosistema. Esa continuidad facilitó su adopción. Sin embargo, la compatibilidad no es absoluta: un programa C válido no siempre es un programa C++ válido.

¿Qué significa «C++ moderno»?

La expresión suele referirse a prácticas y funciones asociadas a C++11 y versiones posteriores: uso sistemático de RAII, contenedores y algoritmos estándar, smart pointers, move semantics, lambdas y otras herramientas para escribir código más expresivo y seguro.

¿Por qué C++ no exige un recolector de basura?

El lenguaje favorece el control determinista de los recursos y evita imponer un recolector o un coste de runtime a todos los programas. RAII, los contenedores y los smart pointers automatizan gran parte de la gestión sin garbage collector obligatorio.

¿Sigue siendo relevante C++ frente a Rust y lenguajes más recientes?

Sí. Su ecosistema, rendimiento, portabilidad nativa y enorme base de software existente siguen siendo ventajas importantes. Rust ofrece garantías distintas de seguridad de memoria y es una alternativa relevante para ciertos proyectos nuevos de sistemas, pero ambos lenguajes conviven en numerosos ámbitos.

¿Por qué C++ no elimina más funciones antiguas al evolucionar?

Porque la compatibilidad con décadas de software tiene un gran valor para su ecosistema. El comité suele preferir añadir mejores mecanismos y cambiar las prácticas recomendadas antes que invalidar bruscamente grandes cantidades de código existente.

¿Te ha resultado útil este artículo?

Fuentes y referencias

Colección

Lenguajes de programación

9 / 26

  1. 01Grace Hopper: de los primeros compiladores a COBOL
  2. 02John Backus: FORTRAN, la notación BNF y el rechazo del código máquina
  3. 03Dennis Ritchie: el lenguaje C en el corazón de Unix
  4. 04FORTRAN: demostrar que un compilador podía competir con el ensamblador
  5. 05El lenguaje C: hacer portables los sistemas sin ocultar la máquina
  6. 06Niklaus Wirth: de Pascal a Oberon, diseñar mediante la simplicidad
  7. 07Bjarne Stroustrup: diseñar C++ sin renunciar al rendimiento
  8. 08Pascal: aprender a programar haciendo visible la estructura
  9. 09C++: de C with Classes al C++ moderno
  10. 10Programación orientada a objetos: objetos, mensajes y abstracciones reutilizables
  11. 11Guido van Rossum: crear Python para que el código sea legible
  12. 12Brendan Eich: JavaScript, del prototipo de Netscape al estándar web
  13. 13James Gosling: el ingeniero que dio origen a Java
  14. 14Python: legibilidad, baterías incluidas y un ecosistema mundial
  15. 15Java: escribir una vez, ejecutar en cualquier lugar
  16. 16JavaScript: el lenguaje que hizo interactiva la Web
  17. 17Ken Thompson: de Unix a Go, la simplicidad como método
  18. 18John McCarthy: Lisp y la idea de programar con símbolos
  19. 19Alan Kay: Smalltalk y el ordenador como medio personal
  20. 20Barbara Liskov: la abstracción que hizo modular el software
  21. 21Robin Milner: ML, la prueba asistida y los lenguajes de la interacción
  22. 22Brian Kernighan: AWK, Unix y el arte de explicar el código
  23. 23Anders Hejlsberg: de Turbo Pascal a C# y TypeScript
  24. 24Larry Wall: Perl, el lenguaje que conectó las herramientas de Internet
  25. 25Yukihiro Matsumoto: Ruby y la felicidad del programador
  26. 26Rasmus Lerdorf: PHP y la democratización de la Web dinámica
BiografíaHistoria de la informáticaPrincipiante

James Gosling: el ingeniero que dio origen a Java

Cómo James Gosling y el equipo Green de Sun diseñaron Java: de Oak y las máquinas virtuales a la portabilidad y el legado del lenguaje.

17 de agosto de 20266 min