Herencia simple

La herencia simple es la más típica, la que se puede encontrar en cualquier lenguaje moderno como Java o C#.
La herencia simple es una relación entre una clase padre (clase base) y una clase hija (clase derivada) llamada "es un tipo de", que muchas veces se abrevia como isA.
La herencia es simple cuando la clase derivada que estamos considerando sólo tiene una clase base.

Un ejemplo sería el siguiente:

#include <iostream>
using namespace std;

class Vehiculo {
public:
void avanza() {}
};

class Coche : public Vehiculo {
public:
void avanza(void)
{ cout << "Avanza coche." << endl; }
};

class Moto: public Vehiculo {
public:
void avanza(void)
{ cout << "Avanza moto." << endl; }
};

int main()
{
Moto t;
Coche c;

t.avanza();
c.avanza();

return 0;
}
Esta es la herencia más útil y típica. Existen otros tipos de herencia marginales en C++, que se describen a continuación, pero que en la práctica son poco útiles.

Más tipos de herencia

Los métodos que coinciden en nombre y en tipos y número de argumentos son sobreescritos, de manera que cuando se llama al método avanza() del objeto c se llama al que realmente corresponde.

Pero, en realidad, existen dos tipos de herencia más: la herencia privada (private), y la herencia protegida (protegida). Ambas modifican la visibilidad de los miembros de la clase base (Vehículo, en el ejemplo), en la clase derivada (Coche o Moto, de nuevo en el ejemplo). Así:

#include <iostream>
using namespace std;

class Vehiculo {
public:
void avanza() { cout << "Avanza vehículo" << endl; }
};

class Coche : private Vehiculo {
};

class Moto: protected Vehiculo {
};

int main()
{
Moto t;
Coche c;

t.avanza();
c.avanza();

return 0;
}
Ahora las líneas t.avanza() y c.avanza() ya no compilan en la función main(), puesto que lo que era público en Vehículo ha pasado a ser privado en Coche, mientras que los mismos miembros de vehículo han pasado a ser protegidos en Moto. De esta manera, es posible crear clases que oculten sus partes Vehículo, y permitan escoger cuáles miembros van a ser visibles y cuáles no.

#include <iostream>
using namespace std;

class Vehiculo {
public:
void avanza() { cout << "Avanza vehículo" << endl; }
};

class Coche : private Vehiculo {
public:
using Vehiculo::avanza;
};

int main()
{
Coche c;

c.avanza();

return 0;
}
Ahora, el programa vuelve a funcionar. Sin embargo, la herencia privada o protegida hacen que realmente la clase se desvincule totalmente de la jerarquía de herehcia. Así, debería ser posible utilizar un Coche en cualquier lugar del programa donde se utilice un Vehículo, sin embargo el compilador no lo permitirá. La razón es que la parte Vehículo dentro de Coche (o de Moto), está escondida y no es accesible (al fin y al cabo, se ha marcado como private o protected).

Estos dos tipos de herencia son, por tanto, muy poco útiles, y en general, también poco recomendables.