Question:
the title is not very descriptive at all, but I put you in situation (I'm learning polymorphism).
Suppose we have two classes:
Base class: CommissionEmployee
Derived class: EmployeeBasePlusCommission
I'm going to create two objects from those classes and two pointers to each object:
EmpleadoPorComision empleadoPorComision("Sue", "Jones", "222-222-2221", 1000, 0.06);
EmpleadoPorComision *empleadoPorComisionPtr = 0;
EmpleadoBaseMasComision empleadoBaseMasComision("Bob", "Lewis", "333-332-1122", 5000, 0.04, 300);
EmpleadoBaseMasComision *empleadoBaseMasComisionPtr = 0;
Now we will call the "print" method. This method belongs to the base class, only that in the derived class, it also has this "print" method and within it the print of the base class + function that displays an attribute of the derived class is called.
Now what I'm going to do is use the print method using those pointers:
empleadoPorComisionPtr = &empleadoPorComision;
empleadoPorComisionPtr->imprimir(); //Invoca a imprimir de la clase base
empleadoBaseMasComisionPtr = &empleadoBaseMasComision;
empleadoBaseMasComisionPtr->imprimir(); //Invoca a imprimir de la clase derivada
So far so good, the problem is when I do this:
empleadoPorComisionPtr = &empleadoBaseMasComision;
empleadoPorComisionPtr->imprimir(); //Invoca a la funcion imprimir de la clase base
This last print() calls print but from the base class. As you can see, in fact, I am telling that last pointer (employeePorCommissionPtr) to point to the employeeBasePlusCommission object, that is, to an object of the derived class, however, why is the print method that it uses the one of the base class, and not the one from the derived class?
Thank you all very much, greetings.
edit:
Definition of the classes:
CommissionEmployee base class definition:
class EmpleadoPorComision
{
public:
EmpleadoPorComision(const string &, const string &, const string &, double=0.0, double=0.0);
void establecerPrimerNombre(const string&); //Establece el primer nombre
string conseguirPrimerNombre() const; //Devuelve el primer conseguirPrimerNombre
void establecerApellidoPaterno(const string&);
string conseguirApellidoPaterno() const;
void establecerNumeroSS(const string&);
string conseguirNumeroSS() const;
void establecerVentasBrutas(double);
double conseguirVentasBrutas() const;
void establecerTarifaComision(double);
double conseguirTarifaComision() const;
double ingresos() const; //Calcula los ingresos
void imprimir() const; //Imprime el objeto EmpleadoPorComision
private:
string primerNombre;
string apellidoPaterno;
string numeroSS;
double ventasBrutas; //Ventas brutas por semana
double tarifaComision; //Porcentaje de comision
};
Defining the derived class EmployeeBasePlusCommission:
class EmpleadoBaseMasComision : public EmpleadoPorComision
{
public:
EmpleadoBaseMasComision(const string&, const string&, const string&, double=0.0, double=0.0, double=0.0);
void establecerSalarioBase(double);
double conseguirSalarioBase() const;
double ingresos() const;
void imprimir() const;
private:
//El resto de miembros de datos se heredan de la clase base.
double salarioBase;
};
Answer:
For the polymorphism to work in this case, that is, to call the function of the child class, it is necessary that the functions to be overridden are labeled as virtual in the base class:
class EmpleadoPorComision
{
// ...
virtual void imprimir() const; //Imprime el objeto EmpleadoPorComision
// ^^^^^^^
};
Additionally, as of C++11, it is recommended to mark functions of derived classes that override a virtual as override
:
class EmpleadoBaseMasComision : public EmpleadoPorComision
{
// ...
void imprimir() const override;
// ^^^^^^^^
};
This way if the function is not going to be overridden (because you've basically screwed up), the compiler will display an error message:
struct Base
{
virtual void func();
virtual void func2() const;
void func3();
};
struct Derivada : Base
{
void func() override; // OK
void func2() override; // ERROR!!!! falta const
void func3() override; // ERROR!!!! la funcion base no es virtual
};
Why doesn't polymorphism work without virtual?
When a normal (not virtual, to be clear) member function is called, the compiler generates a direct function call, i.e. in the following example:
struct Base
{
void func();
};
struct Derivada : Base
{
void func();
};
Base* base = new Derivada;
base->func();
Since the pointer is of type base
, the compiler will generate a call to Base::func
even though Derivada::func
exists.
Why?
Basically, because non-virtual calls are computed at compile time, and since at compile time the compiler only has the pointer of type Base
, the function to execute will be Base::func
.
This is because the intention of C++ has always been to optimize it for speed, so all possible optimizations are applied to the generated code.
And what if the function is virtual?
If you declare the function of the base class as virtual
, what happens is that during the compilation process, a function pointer is generated in the base class. This function pointer will point to the appropriate version, so that we can call functions of the child class from the parent class:
struct Base
{
virtual void func(); // <<--- Genera un puntero a funcion
};
struct Derivada : Base
{
void func() override; // <<--- Sobreescribe el puntero a funcion de la clase padre
};
Base* base = new Derivada;
base->func(); // Se realiza la llamada a traves del puntero a funcion
The function pointers I'm talking about are not visible. However, its effect can be seen in that calls to virtual functions are significantly slower (instead of a direct call, a function pointer is called).