Saltar al contenido
Portada » C/C++ » 10. Diferencias entre C y C++

10. Diferencias entre C y C++

Diferencias entre C y C++. En este capítulo daremos el salto de C a C++, un lenguaje que extiende a su antecesor con características importantes como la posibilidad de programación orientada a objetos, plantillas, manejo avanzado de memoria y una biblioteca estándar mucho más rica. Analizaremos las ventajas clave que aporta C++ sobre C, revisaremos su sintaxis específica (por ejemplo, la inicialización de variables y las clases), y compararemos la nueva cabecera <iostream> con las funciones clásicas de stdio.h. También aprenderás a trabajar con la clase std::string para gestionar cadenas, a utilizar espacios de nombres (namespace) para organizar código y evitar colisiones, y a aplicar la sobrecarga de funciones, una técnica que permite reutilizar el mismo nombre de función con diferentes parámetros. Empezamos!!!!

10.1 Ventajas de C++ sobre C

Aunque C y C++ comparten muchas similitudes —de hecho, C++ fue originalmente una extensión de C llamada “C con clases”—, C++ introduce una serie de mejoras fundamentales que lo convierten en una opción más moderna, estructurada y potente para el desarrollo de software. A continuación, analizamos con detalle las principales ventajas de C++ sobre C:

1. Programación orientada a objetos (OOP)

C++ incorpora de forma nativa el paradigma orientado a objetos, que permite estructurar programas en torno a clases y objetos. Esto ofrece beneficios significativos como:

  • Encapsulamiento: puedes agrupar datos y funciones dentro de una misma clase, limitando el acceso externo a ciertos miembros mediante modificadores como private, public y protected.
  • Herencia: puedes crear nuevas clases a partir de otras existentes, reutilizando código y extendiendo funcionalidades.
  • Polimorfismo: permite tratar objetos derivados como si fueran del tipo base.

Ejemplo: En C++ puedes definir una clase Persona con atributos y métodos, algo que en C requeriría estructuras y punteros a funciones.

class Persona {
public:
string nombre;
int edad;

void saludar() {
cout << "Hola, me llamo " << nombre << " y tengo " << edad << " años." << endl;
}
};

2. Manejo avanzado de cadenas con std::string

A diferencia de C, que trata las cadenas como arreglos de caracteres (char[]), C++ incluye la clase std::string, mucho más segura y flexible:

  • Permite concatenación directa con el operador +
  • Tiene métodos como .length(), .substr(), .find(), etc.
  • Se gestiona dinámicamente (no necesitas preocuparte por el tamaño del array o por el carácter \0 al final)

Ejemplo:

string nombre = "Juan";
string saludo = "Hola " + nombre;
cout << saludo << endl; // Salida: Hola Juan

3. Biblioteca Estándar (STL)

C++ ofrece Standard Template Library (STL), esta librería incluye estructuras de datos listas para usar como:

  • vector (arreglos dinámicos)
  • map (diccionarios)
  • set (conjuntos)
  • list, stack, queue, entre otras.

Además, C++ puedes usar plantillas (templates), que hacen posible escribir funciones y clases genéricas.

4. Sobrecarga de funciones y operadores

C++ permite definir múltiples funciones con el mismo nombre, diferenciándolas por su lista de parámetros (sobrecarga). También puedes redefinir el comportamiento de operadores (+, -, ==, etc.) para tipos definidos por el usuario.

Ejemplo: Sobrecargar + para una clase Punto de representación de coordenadas:

class Punto {
public:
int x, y;

Punto(int _x, int _y) : x(_x), y(_y) {}

Punto operator+(const Punto& otro) {
return Punto(x + otro.x, y + otro.y);
}
};

5. Mejor manejo de memoria y recursos

C++ mejora la gestión de memoria respecto a C con herramientas como:

  • Constructores y destructores automáticos
  • Operadores new y delete en lugar de malloc y free
  • Tipos RAII (Resource Acquisition Is Initialization), lo que permite liberar recursos de forma automática al salir del ámbito.

6. Espacios de nombres (namespace)

En C++, puedes usar namespaces para evitar colisiones entre nombres de variables, funciones o clases.

Ejemplo:

namespace utilidades {
void mostrarMensaje() {
cout << "Desde el namespace utilidades" << endl;
}
}

int main() {
utilidades::mostrarMensaje();
return 0;
}

10.2 Sintaxis específica de C++

Aunque C++ mantiene casi toda la sintaxis base de C (sentencias, estructuras de control, funciones, etc.), introduce una serie de ampliaciones sintácticas que permiten trabajar de forma más modular.

Veamos las principales diferencias de sintaxis que distinguen a C++ de C, y cómo se utilizan en la práctica.

1. Declaración de variables en cualquier parte del código

En C, las variables deben declararse al principio de un bloque {}. En C++, se pueden declarar en cualquier punto, lo que permite una mayor claridad y coherencia al escribir código.

  • C (obligatorio al principio):
int main() {
int a = 10;
int b = 5;

if (a > b) {
int c = a - b; // En C esto puede causar error si se declara dentro de un bloque sin estar al inicio.
printf("%d\n", c);
}
return 0;
}
  • C++ (permitido en cualquier lugar):
int main() {
int a = 10;
int b = 5;

if (a > b) {
int c = a - b; // Correcto y común en C++
cout << c << endl;
}
return 0;
}

2. Uso del tipo bool y constantes true y false

En C, no existe un tipo de dato bool (se suele usar int y tratar 0 como falso). C++ incorpora directamente el tipo bool y las constantes true y false.

Ejemplo:

bool esMayor = (10 > 5); // true
if (esMayor) {
cout << "Es verdadero." << endl;
}

3. Entrada y salida estándar con cin y cout

En lugar de usar printf() y scanf(), C++ utiliza el sistema de entrada/salida basado en flujos:

  • cout para salida estándar
  • cin para entrada estándar
  • Ejemplo:
#include <iostream>
using namespace std;

int main() {
int edad;
cout << "Introduce tu edad: ";
cin >> edad;
cout << "Tienes " << edad << " años." << endl;
return 0;
}

Este sistema permite formatear la salida de forma más flexible, y encadena múltiples elementos con el operador <<.

4. Constructores y destructores

Las clases en C++ pueden tener funciones especiales que se ejecutan automáticamente al crear o destruir un objeto:

  • Constructor: se llama al crear el objeto.
  • Destructor: se llama al destruir el objeto (por ejemplo, cuando termina su ámbito de vida).
  • Ejemplo:
class Persona {
public:
string nombre;

Persona(string n) {
nombre = n;
cout << "Persona creada: " << nombre << endl;
}

~Persona() {
cout << "Persona destruida: " << nombre << endl;
}
};

5. Plantillas (templates)

Las plantillas permiten definir funciones y clases genéricas, que se adaptan automáticamente al tipo de dato que se les pase.

  • Ejemplo de función plantilla:
template <typename T>
T sumar(T a, T b) {
return a + b;
}

int main() {
cout << sumar(3, 4) << endl; // int
cout << sumar(3.2, 1.8) << endl; // double
}

6. Uso de referencias (&)

C++ permite pasar variables por referencia a funciones, evitando el uso explícito de punteros. Esto es más intuitivo y seguro en muchos contextos.

  • Ejemplo:
void duplicar(int& valor) {
valor *= 2;
}

int main() {
int x = 5;
duplicar(x);
cout << x << endl; // Salida: 10
}

7. Sobrecarga de funciones

Puedes definir varias funciones con el mismo nombre pero distinta cantidad o tipo de parámetros. Esto permite escribir interfaces más limpias y expresivas.

  • Ejemplo:
int sumar(int a, int b) {
return a + b;
}

double sumar(double a, double b) {
return a + b;
}

10.3 iostream frente a stdio.h

Una de las diferencias fundamentales entre C y C++ radica en el sistema de entrada/salida. Mientras que C utiliza la biblioteca stdio.h (standard input/output), C++ introduce una alternativa más moderna y segura: iostream.

Veamos las diferencias entre ambos.

1. ¿Qué es stdio.h?

En C, la entrada y salida se realizan mediante funciones como:

  • printf() → Imprime en pantalla
  • scanf() → Lee datos desde teclado
  • fprintf() / fscanf() → I/O en archivos
  • putchar() / getchar() → Entrada/salida de caracteres
  • Ejemplo en C (stdio.h):
r#include <stdio.h>

int main() {
int edad;
printf("Introduce tu edad: ");
scanf("%d", &edad);
printf("Tienes %d años.\n", edad);
return 0;
}

2. ¿Qué es iostream?

C++ ofrece iostream (Input/Output Stream), una biblioteca basada en el concepto de flujos de datos (streams). Sus principales elementos son:

  • cout → Imprime en pantalla (console output)
  • cin → Lee desde teclado (console input)
  • cerr → Salida estándar de errores
  • clog → Salida estándar para logs (sin bloquear flujo)
  • Ejemplo en C++ (iostream):
#include <iostream>
using namespace std;

int main() {
int edad;
cout << "Introduce tu edad: ";
cin >> edad;
cout << "Tienes " << edad << " años." << endl;
return 0;
}

3. Diferencias clave entre stdio.h y iostream

Característicastdio.hiostream
EstiloProcedural (C)Orientado a objetos (C++)
SintaxisVerbosa y propensa a erroresLimpia y legible
Tipo de datosNo detecta errores de tipoUsa tipos fuertemente tipados
InternacionalizaciónRequiere formateo manualCompatible con locale
ExtensibilidadLimitadaAltamente extensible
Sobrecarga de operadoresNo soportaSí (<< y >> para I/O)
Entrada/salida personalizadaDifícil con estructuras propiasFácil con operadores sobrecargados

Veamos algunos ejemoplos comparativos.

// C
int x = 10;
printf("Valor: %d\n", x);
// C++
int x = 10;
cout << "Valor: " << x << endl;

Y con múltiples valores:

// C
int a, b;
scanf("%d %d", &a, &b);
// C++
int a, b;
cin >> a >> b;

Ojo, Errores comunes que se suele cometer en scanf()

  • Olvidar el & en scanf()
  • Usar el formato incorrecto (ej. %f en lugar de %lf)

5. ¿Cuándo usar cada uno?

CasoRecomendación
Programas en Cstdio.h
Programas modernos en C++iostream
Entrada/salida rápida para competicionesstdio.h (más veloz sin sincronización)
Personalización y extensibilidadiostream (clases y objetos)

10.4 Manejo de cadenas con string en C++

En C, las cadenas se manejan como arrays de caracteres terminados en '\0', lo que obliga a utilizar funciones de la biblioteca <string.h> para su manipulación. En C++, aunque se pueden seguir usando las cadenas estilo C, se recomienda usar la clase std::string del encabezado <string>, que proporciona una forma más segura, flexible y sencilla de trabajar con texto.

1. ¿Qué es std::string?

std::string es una clase de la biblioteca estándar de C++ que permite trabajar con cadenas de texto. Al ser una clase, incluye métodos y operadores sobrecargados que facilitan tareas comunes como concatenar, comparar, buscar o extraer subcadenas.

Incluye automáticamente:

  • Gestión dinámica de memoria.
  • Comparación de cadenas con ==, <, etc.
  • Concatenación con + o +=.
  • Acceso por índice con [].

2. Incluir string y sintaxis básica

Como cualquier librería, para utilizarla debemos incluirla con la sentencia #include al principio del programa

#include <iostream>
#include <string>
using namespace std;

int main() {
string nombre = "Juan";
cout << "Hola " << nombre << endl;
return 0;
}

3. Operaciones comunes con string

Al ser String una clase, nos ofrece un conjunto de métodos a los que podemos invocar y que facilitan la manipulación de las cadenas de caracteres. Veamos los más importantes.

  • Concatenación. Une dos cadenas de caracteres.
string saludo = "Hola";
string nombre = "Ana";
string mensaje = saludo + " " + nombre;
cout << mensaje << endl; // Hola Ana
  • Longitud. Devuelve el tamaño de la cadena de caracteres
string texto = "Programación";
cout << "Longitud: " << texto.length() << endl;
  • Acceso a caracteres. Devuelve el carácter de la cadena de la posición N, indicado entre []
string palabra = "C++";
cout << palabra[0]; // 'C'
palabra[1] = '#'; // ahora la cadena es "C#+"
  • Comparación Compara dos cadenas de caracteres.
string a = "Hola", b = "Adiós";
if (a > b) cout << "a es mayor alfabéticamente" << endl;
  • Subcadenas. Extrae una cadena de caracteres de otra, indicando la posición inicial y el número de caracteres que se quiere extraer.
string frase = "Lenguaje C++";
string parte = frase.substr(9, 3); // "C++"
  • Buscar dentro de una cadena. Busca una cadena de caracteres dentro de otra y devuelve la posición si existe.
string frase = "Hola mundo";
size_t pos = frase.find("mundo");
if (pos != string::npos)
cout << "Encontrado en posición: " << pos << endl;
  • Eliminar parte de una cadena. Elimina una cadena de caracteres de otra.
string texto = "Hola mundo cruel";
texto.erase(10, 6); // Borra "cruel"
cout << texto; // Hola mundo

4. Conversión entre string y tipos primitivos

En C++ podemos realizar conversiones de una variable entre distintos tipos. En ocasiones es necesario poder realizar estas conversiones, veamos unos ejemplos:

  • De string a int / float
#include <string>
#include <iostream>
using namespace std;

int main() {
string numero = "123";
int valor = stoi(numero);
float real = stof("3.14");
cout << valor << " y " << real << endl;
return 0;
}
  • De int / float a string
int edad = 30;
string texto = to_string(edad);
cout << "Tienes " + texto + " años." << endl;

5. Comparación con cadenas estilo C

Veamos con una tabla resumen las diferencias entre C y C++ para el manejor de cadenas de texto.

Característicachar[] (C)string (C++)
Necesita \0No
Memoria manualNo
Concatenaciónstrcat()+ o +=
Comparaciónstrcmp()==, <, etc.
SubcadenasManual (strncpy)substr()
Lectura con espaciosDifícil (gets, fgets)Fácil con getline()

6. Leer líneas completas

Otra de las diferencias que nos ofrece C++ con respecto a C es la poisibilidad de leer cadenas de texto completas hasta que encuentra un ‘\n’.

string linea;
cout << "Introduce una frase: ";
getline(cin, linea); // permite leer espacios
cout << "Has dicho: " << linea << endl;

10.5 Espacios de nombres (namespace) en C++

En programas grandes, es común que diferentes partes del código usen los mismos nombres para variables, funciones o clases. Para evitar conflictos de nombres, C++ introduce el concepto de espacios de nombres o namespaces.

¿Qué es un namespace?

Un namespace es un contenedor que encapsula identificadores (como funciones, variables o clases) bajo un nombre específico. De esta forma, se pueden organizar mejor los elementos del código y evitar que haya conflictos con nombres repetidos.

Sintaxis básica

namespace MiEspacio {
int valor = 42;

void saludar() {
std::cout << "Hola desde MiEspacio" << std::endl;
}
}

Para acceder a lo que hay dentro del namespace:

MiEspacio::saludar();       // llama a la función
std::cout << MiEspacio::valor << std::endl;

Ventajas del uso de namespaces

  • Permiten modularizar el código.
  • Evitan conflictos con nombres repetidos.
  • Son especialmente útiles cuando se usan librerías externas.

std — El espacio de nombres estándar

En C++, muchas funciones y clases de la biblioteca estándar (como cout, cin, string) están dentro del namespace std.

#include <iostream>

int main() {
std::cout << "Hola mundo" << std::endl;
return 0;
}

Alternativamente, se puede hacer uso de la sentencia using para indicar el espacion de nombres a utilizar:

using namespace std;

int main() {
cout << "Hola mundo" << endl;
return 0;
}

Alias de namespace

También es posible crear un alias para un namespace largo:

namespace ProyectoLargoNombre = MiEspacio;
ProyectoLargoNombre::saludar();

Namespaces anidados

Los espacios de nombres pueden estar dentro de otros:

namespace A {
namespace B {
void mensaje() {
std::cout << "Desde A::B" << std::endl;
}
}
}

A::B::mensaje(); // Acceso al namespace anidado

Veamos un ejemplo completo de como se utilizaría:

#include <iostream>
using namespace std;

namespace Matematicas {
double pi = 3.1416;

double cuadrado(double x) {
return x * x;
}
}

int main() {
cout << "PI = " << Matematicas::pi << endl;
cout << "Cuadrado de 5: " << Matematicas::cuadrado(5) << endl;
return 0;
}

10.6 Sobrecarga de funciones en C++

La sobrecarga de funciones (function overloading) es una característica de C++ que permite definir múltiples funciones con el mismo nombre, pero con parámetros diferentes. Esta es una de las formas en que C++ admite polimorfismo.

¿Qué es la sobrecarga de funciones?

Es cuando se declaran varias funciones con el mismo nombre pero con una diferente lista de parámetros (tipo, número o ambos). El compilador decide cuál función ejecutar dependiendo de los argumentos que se le pasen.

Ejemplo básico

#include <iostream>
using namespace std;

void saludar() {
cout << "Hola" << endl;
}

void saludar(string nombre) {
cout << "Hola, " << nombre << endl;
}

void saludar(string nombre, int edad) {
cout << "Hola, " << nombre << ". Tienes " << edad << " años." << endl;
}

int main() {
saludar();
saludar("María");
saludar("Carlos", 30);
return 0;
}

Salida:

Hola
Hola, María
Hola, Carlos. Tienes 30 años.

Reglas de la sobrecarga

Para que la sobrecarga sea válida, las funciones deben diferir en:

  • Número de parámetros
  • Tipo de parámetros
  • Orden de parámetros
//  Esto no es válido solo por cambiar el tipo de retorno
int suma(int a, int b);
float suma(int a, int b); // Error

Veasmos algunos ejemplos con funciones matemáticas

int suma(int a, int b) {
return a + b;
}

float suma(float a, float b) {
return a + b;
}

double suma(double a, double b) {
return a + b;
}

Sobrecarga con parámetros por defecto

La sobrecarga también puede coexistir con valores por defecto, aunque hay que tener cuidado para no generar ambigüedades:

void imprimir(int a, int b = 0) {
cout << "a: " << a << ", b: " << b << endl;
}

void imprimir(string texto) {
cout << "Texto: " << texto << endl;
}

Beneficios de la sobrecarga

  • Facilita la legibilidad del código.
  • Permite construir interfaces más intuitivas.
  • Reduce la necesidad de inventar nombres distintos para cada versión de una función.

Conclusión

En este capítulo hemos visto las principales diferencias entre C y C++. Aprendimos las ventajas de C++, su sintaxis más moderna, el uso de iostream para entrada/salida, el manejo de cadenas con string, la utilidad de los namespace para evitar conflictos, y la sobrecarga de funciones como forma de polimorfismo. Vayamos a practicar con unos ejercicios propuestos.

Ejercicio 1 – Calculadora básica con sobrecarga de funciones
Enunciado
Crea un programa en C++ con una función llamada calcular sobrecargada tres veces para sumar int, sumar double y concatenar dos std::string. Desde main() pide al usuario dos valores; detecta si son enteros, reales o palabras (sin espacios) y muestra el resultado usando la versión de calcular adecuada.

Código:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

// Sobrecargas
int    calcular(int a, int b)           { return a + b; }
double calcular(double a, double b)     { return a + b; }
string calcular(const string& a, const string& b) { return a + b; }

bool esEntero(const string& s) {
    if (s.empty()) return false;
    size_t i = (s[0] == '-' || s[0] == '+') ? 1 : 0;
    for (; i < s.size(); ++i) if (!isdigit(s[i])) return false;
    return true;
}

bool esReal(const string& s) {
    stringstream ss(s);
    double d;
    char c;
    return (ss >> d) && !(ss >> c);     // true si se leyó un double y no sobra nada
}

int main() {
    string x, y;
    cout << "Introduce dos valores: ";
    cin  >> x >> y;

    if (esEntero(x) && esEntero(y)) {
        cout << "Suma entera: "
             << calcular(stoi(x), stoi(y)) << endl;
    } else if (esReal(x) && esReal(y)) {
        cout << "Suma real: "
             << calcular(stod(x), stod(y)) << endl;
    } else {
        cout << "Concatenación: "
             << calcular(x, y) << endl;
    }
    return 0;
}

Explicación

  • Tres funciones calcular con firmas distintas ilustran sobrecarga de funciones.
  • Funciones auxiliares detectan si las entradas son entero, real o texto.
  • Se llaman stoi y stod para convertir cadenas a sus tipos numéricos.
Ejercicio 2 – Gestor de personas con std::string y namespace
Enunciado
Define un espacio de nombres agenda que contenga la clase Persona. La clase guarda nombre (std::string) y edad, e implementa un método presentarse(). En main() crea dos objetos Persona y llama a sus métodos.

Código:

#include <iostream>
#include <string>

namespace agenda {

class Persona {
    std::string nombre;
    int edad;
public:
    Persona(std::string n, int e) : nombre(n), edad(e) {}
    void presentarse() const {
        std::cout << "Soy " << nombre
                  << " y tengo " << edad << " años.\n";
    }
};

} // namespace agenda

int main() {
    agenda::Persona p1("Lucía", 28);
    agenda::Persona p2("Diego", 35);

    p1.presentarse();
    p2.presentarse();
    return 0;
}

Explicación

  • Se usa namespace agenda para encapsular la clase y evitar colisiones.
  • std::string simplifica la gestión de texto sin preocuparse por tamaños ni \0.
  • Constructor inicializa miembros; el método presentarse() imprime usando cout.
Ejercicio 3 – Conversor de temperaturas con iostream y referencias
Enunciado
Implementa dos funciones: celsiusToFahrenheit(double c) y fahrenheitToCelsius(double f) que devuelvan la temperatura convertida. Pide al usuario elegir el sentido de la conversión y mostrar el resultado con iostream.

Código:

#include <iostream>
using namespace std;

// Funciones de conversión
double celsiusToFahrenheit(const double& c)     { return c * 9.0/5 + 32; }
double fahrenheitToCelsius(const double& f)     { return (f - 32) * 5.0/9; }

int main() {
    char opcion;
    double valor;

    cout << "Conversor de temperatura\n";
    cout << "a) Celsius -> Fahrenheit\n";
    cout << "b) Fahrenheit -> Celsius\n";
    cout << "Elige opción (a/b): ";
    cin  >> opcion;

    if (opcion == 'a' || opcion == 'A') {
        cout << "Introduce grados Celsius: ";
        cin  >> valor;
        cout << "Fahrenheit: "
             << celsiusToFahrenheit(valor) << endl;
    } else if (opcion == 'b' || opcion == 'B') {
        cout << "Introduce grados Fahrenheit: ";
        cin  >> valor;
        cout << "Celsius: "
             << fahrenheitToCelsius(valor) << endl;
    } else {
        cout << "Opción no válida.\n";
    }
    return 0;
}

Explicación

  • Se utiliza iostream (cin/cout) para I/O en lugar de scanf/printf.
  • Las funciones reciben sus argumentos por referencia constante para evitar copias innecesarias y muestran la sintaxis de C++ moderno.
  • El programa demuestra control de flujo y operaciones simples con funciones separadas para cada conversión.
Logo C++

Bibliografía del tutorial de C/C++.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *