2

旅游和导游。GuideTour 扩展了 Tour。我创建了这些项目的列表并将它们添加到向量中。

 list = new vector<Tour>(); 
 list->push_back(Tour("FP001", "Fun Park 3 Day Pass", 110.00));
 list->push_back(Tour("BG002", "Botanical Gardens Entry Pass", 30.00));
 list->push_back(GuidedTour("SK003", "Learn to Ski Adventure Tour", 240.00, "28/07/2008", "Zail S", 25));
 list->push_back(Tour("OZ004", "Open Range Zoo Entry Pass", 45.00));
 list->push_back(GuidedTour("AB005", "Abseiling for Beginners Tour", 120.00, "15/07/2008", "Rex P", 35));
 list->push_back(GuidedTour("RA006", "White Water Rafting Tour", 200.00, "22/06/2008", "Clint R", 16));

然后我想通过这个数组并检查这些对象的类型

void TourManager::callDisplayOnEach() {
    for (vector<Tour>::iterator it = list->begin(); it != list->end(); ++it) {
        if (typeid(*it) == typeid(GuidedTour)) {
            cout << "Guided Tour" << "\n";
        }
        else { 
            cout << "NOT Guided Tour : " << typeid(*it).name() << "\n"; 
        }
        //(*it).display();
    }
}

但是,它始终返回 NOT 导游选项。

4

4 回答 4

2

参考 Mat 的链接:

通过存储指向基类的指针,就不会进行切片,您也可以实现所需的多态行为

所以创建一个向量

list = new vector<Tour*>(); 

而不是

list = new vector<Tour>(); 
于 2013-08-21T05:39:52.243 回答
2

正如上面的评论所说,这是因为slicing。由于您将存储在您的vector,而不是引用指针中,因此当您将值复制到容器中时(是的,它们被复制了!),然后每个对象都被截断为基类Tour

于 2013-08-21T05:40:47.863 回答
0

我同意下面的其他答案,即这是一个切片问题,尽管我会将其设为 unique_ptrs 的向量,以便它在释放时为您管理内存。请参阅下面的我的版本。此外,在基类中添加了一个虚拟析构函数,这在您通过基指针引用派生类时是一个好主意,以避免在通过基指针进行析构时切片。

#include <iostream>
#include <memory>
#include <vector>

class Tour
{

  public:
  Tour(const std::string& tt, const std::string& desc, double p  ) : tourType_(tt), description_(desc), price_(p){}

  virtual void display () const
  {
    std::cout << "Standard Tour" << std::endl;
  }

  virtual ~Tour() {};

  protected:
  std::string tourType_;
  std::string description_;
  double price_;
};

class GuidedTour : public Tour
{

  public:
  GuidedTour(const std::string& tt, const std::string& desc, double p, const std::string& date, const std::string& name, int age  ) : Tour(tt,desc,p), date_(date), guideName_(name), guideAge_(age) {}


  void display () const 
  {
    std::cout << "Guided Tour" << std::endl;
  }

  private:
  std::string date_;
  std::string guideName_;
  int guideAge_;
};


int main ( int argc, char *argv[] )
{
  std::vector<std::unique_ptr<Tour> > v;

  v.emplace_back(new Tour("FP001", "Fun Park 3 Day Pass", 110.00));
  v.emplace_back(new Tour("BG002", "Botanical Gardens Entry Pass", 30.00));
  v.emplace_back(new GuidedTour("SK003", "Learn to Ski Adventure Tour", 240.00, "28/07/2008", "Zail S", 25));
  v.emplace_back(new Tour("OZ004", "Open Range Zoo Entry Pass", 45.00));
  v.emplace_back(new GuidedTour("AB005", "Abseiling for Beginners Tour", 120.00, "15/07/2008", "Rex P", 35));
  v.emplace_back(new GuidedTour("RA006", "White Water Rafting Tour", 200.00, "22/06/2008", "Clint R", 16));

  for ( auto& i : v )
  {
    i->display();
  }
}
于 2013-08-21T06:36:21.763 回答
0

就像说的那样,有Slicing

当您vector存储Tour对象(基类)时,要存储的对象()的所有派生对象特定成员GuidedTour将在复制期间被切掉以充当基类对象。

解决方案是存储基类的指针:

std::vector<Tour*> list;

由于您正在存储指针,因此不再有对象副本,也没有对象切片。

最好的办法是使用smart pointers不必手动进行内存管理:

std::vector<std::unique_ptr<Tour>> list;

但是如果你使用智能指针,你将不得不使用std::vector::emplace_back()而不是push_back

std::vector<std::unique_ptr<Tour>> list;

list.emplace_back(new Tour);
list.emplace_back(new GuidedTour);
list.emplace_back(new Tour);
list.emplace_back(new GuidedTour);
list.emplace_back(new Tour);

活生生的例子

但这些技术意味着使用 C++11。

于 2013-08-21T07:24:50.973 回答