Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

member variable polymorphism & argument by reference

Tags:

c++

I'm new to C++ and have a question about member variable polymorphism. I have the following class definitions -

class Car
{
    public:
        Car();
        virtual int getNumberOfDoors() { return 4; }
};

class ThreeDoorCar : public Car
{
    public:
        ThreeDoorCar();
        int getNumberOfDoors() { return 3; }
};

class CarPrinter
{
    public:
        CarPrinter(const Car& car);
        void printNumberOfDoors();

    protected:
        Car car_;
};

and implementation

#include "Car.h"

Car::Car()
{}

ThreeDoorCar::ThreeDoorCar()
{}

CarPrinter::CarPrinter(const Car& car)
: car_(car)
{}

void CarPrinter::printNumberOfDoors()
{
    std::cout << car_.getNumberOfDoors() << std::endl;
}

The problem is when I run the following, the getNumberOfDoors of the parent class is called. I can get around this issue by making the member variable Car a pointer, but I prefer to pass in the input by reference instead of by pointer (which I understand to be preferred). Could you tell me what I'm doing wrong? Thanks!

ThreeDoorCar myThreeDoorCar;
std::cout << myThreeDoorCar.getNumberOfDoors() << std::endl;

CarPrinter carPrinter(myThreeDoorCar);
carPrinter.printNumberOfDoors();
like image 298
haginile Avatar asked Jun 11 '13 03:06

haginile


People also ask

What is a member variable C++?

In object-oriented programming, a member variable (sometimes called a member field) is a variable that is associated with a specific object, and accessible for all its methods (member functions).

Should member variables be initialized?

You should always initialize native variables, especially if they are class member variables. Class variables, on the other hand, should have a constructor defined that will initialize its state properly, so you do not always have to initialize them.

What is C++ polymorphism?

Polymorphism in C++ means, the same entity (function or object) behaves differently in different scenarios. Consider this example: The “ +” operator in c++ can perform two specific functions at two different scenarios i.e when the “+” operator is used in numbers, it performs addition.

What is required for polymorphism in C++?

Polymorphism in C++ Typically, polymorphism occurs when there is a hierarchy of classes and they are related by inheritance. C++ polymorphism means that a call to a member function will cause a different function to be executed depending on the type of object that invokes the function.


2 Answers

By making a copy of the object you sacrifice its polymorphic abilities. Whatever type of car you pass, the copy will be of type Car (the base class), because that is what it is declared as.

If you want to keep using polymorphism either use a pointer or a reference. Here is the version using a reference:

class CarPrinter
{
public:
    CarPrinter(const Car& car);
    void printNumberOfDoors();

protected:
    const Car &car_;     // <<= Using a reference here
};

As you can see, this way you can continue using a constructor that takes a reference as argument. (These references don't have to be const, although const makes sense as long as the purpose of the CarPrinter is just printing.)

One potentially undesirable side-effect of this is that you can't change what the reference refers to after constructing the CarPrinter object. If you need to print the information for a different object, you'll have to create a new CarPrinter object for that. These objects would then really just act as (probably short-lived) wrappers around references.

If you don't like this, you can still continue passing a reference to the constructor, but turn it into a pointer by taking its address in the constructor implementation and then storing that.

like image 176
jogojapan Avatar answered Oct 13 '22 01:10

jogojapan


When you do:

Car m_car;

It will not treat the m_car instance polymorphically, even if Car has subclasses and virtual functions. It will just use Car functions. This is called static binding - it determines which function to call at compile time based on the static type (Car) .

You need a reference or pointer for it to be handled polymorphically via dynamic dispatch by looking up the correct virtual function via the virtual function table of the instance's dynamic type (e.g. ThreeDoorCar or TwoDoorCar etc) at runtime. Polymorphic call behaviour is achieved through pointers or references in combination with virtual function declarations. This is more or less a direct result of syntactically using values vs pointers/refs (See @kfmfe04's comment below).

Car* pCar;
Car& rCar = x_car;

Virtual members called via a pointer or reference (e.g. pCar->getNumberOfDoors() or rCar.getNumberOfDoors()) does a vtable lookup at run time (dynamic dispatch). Because only at runtime does it know the dynamic type of the instance.

But m_car.getNumberOfDoors() is a virtual member that is called directly, and the compiler knows at compile time the direct (static) type and function address, statically binding the function address (Car::getNumberOfDoors) at compile time.

like image 43
Preet Kukreti Avatar answered Oct 13 '22 00:10

Preet Kukreti