Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ overridden virtual function not getting called [duplicate]

Tags:

c++

I have the following setup:

main.cpp:

int main()
{
    vector <Tour> tourList;
    Tour* tour_ptr;

    for (unsigned int i = 0; i < tourList.size(); i++)
    {
        tour_ptr = &tourList[i];
        tour_ptr->display();
    }
}

Tour.h:

class Tour
{
   public:
    virtual void display();
};

Tour.cpp:

void Tour::display()
{
    cout << "Tour ID: " << getID() << "\n";
    cout << "Description: " << getdescription() << "\n";
    cout << "Tour Fee: $" << getfee() << "\n";
    cout << "Total Bookings: " << getbookings() << "\n\n";
}

GuidedTour.h:

class GuidedTour : public Tour
{
    public:
            void display();
};

GuidedTour.cpp:

void GuidedTour::display()
{
    Tour::display();
    cout << "Max Tour Group Size: " << getMaxTourists() << "\n";
    cout << "Tour Guide: " << getGuideName() << "\n";
    cout << "Tour Date: " << getTourDate() << "\n\n";
}

GuidedTour inherits from the Tour class, and I've specified the display() function as virtual in the base Tour class, but for some reason, the GuidedTour display() function never gets called, only the base function gets called every time. What am I doing wrong?

like image 638
user2742003 Avatar asked Sep 17 '13 05:09

user2742003


2 Answers

Your code actually doesn't print anything as the std::vector would initially be empty. Other than that, your problem is caused by object slicing (I'm assuming that you are push_back()ing GuidedTours into the vector).

When object slicing takes place, you are storing only the Tour part of your GuidedTour object(s), and that's the reason why you are seeing the output of Tour::display().

To solve your problem, you need to store the objects polymorphically, by using (smart) pointers and dynamically-allocating your objects.

int main()
{
    vector <std::unique_ptr<Tour>> tourList;

    for(...) {
       tourList.push_back(std::make_unique<GuidedTour>(/* constructor parameters */));
       ...
       tourList.push_back(std::make_unique<Tour>(/* constructor parameters */));
    }

    for (unsigned int i = 0; i < tourList.size(); i++)
    {
        tourList[i]->display();
    }
}

Notice that I am using std::unique_ptr/std::make_unique and not raw newed pointers. Using them would greatly ease you of the problem of manually managing and deleteing your objects, which sometimes[understatement] are the cause of bugs and undefined behavior.

Note that some people might suggest you to use boost::ptr_vector or something similar. Listen to them, especially if they give you arguments on why they are better than the alternatives.

like image 180
Mark Garcia Avatar answered Oct 30 '22 16:10

Mark Garcia


Your problem has nothing to do with your classes, rather how you are creating the object. Each element in the tourList vector is a tour, and nothing at compile time or runtime is there to determine that they are GuidedTours. In effect, GuidedTour is never called, because I don't see a GuidedTour object in your main anywhere.

like image 25
It'sPete Avatar answered Oct 30 '22 17:10

It'sPete