7

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?

user2742003
  • 91
  • 1
  • 4
  • 2
    In your vector you should store Tour* not instances of Tour otherwise you cannot store GuidedTour instances in it. – AndersK Sep 17 '13 at 05:04
  • You are suffering from slicing. Your GuidedTour is being sliced into a Tour when placed into the vector. – Martin York Sep 17 '13 at 05:06
  • So I googled "object slicing" and apparently the solution is to make the base class pure virtual. That is not an option for me, because I need to be able to instantiate objects of the base Tour class. What other options do I have? – user2742003 Sep 17 '13 at 05:13
  • That is not the solution. The solution is not to downcast objects by value. – user207421 Sep 17 '13 at 06:11
  • @user2742003: The `vector` holds `Tour` objects. It can NOT hold `GuidedTour` objects so if you push one into the vector it slices off the Tour part and puts it in the vector. If you want to hold polymorphic objects in a vector you need to use pointers `std::vector` or preferably `boost::ptr_vector` – Martin York Sep 17 '13 at 08:37

3 Answers3

11

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.

Mark Garcia
  • 17,424
  • 4
  • 58
  • 94
2

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.

It'sPete
  • 5,083
  • 8
  • 39
  • 72
  • I actually removed the the Tour and GuidedTour objects that I push_back'ed into the vector from the examples above , to save on space and make it more readable. – user2742003 Sep 17 '13 at 05:26
  • Ah, well then, see Mark's answer. By pushing onto a queue of Tours you are stripping away the GuidedTour portion of the object. – It'sPete Sep 17 '13 at 05:28
-1

I am agree with "It'sPete". because you haven't used the GuidedTour class. It will work if you use the following method.

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

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