【问题标题】:Virtual Method not calling dervied class method. - C++虚拟方法不调用派生类方法。 - C++
【发布时间】:2011-12-01 22:04:57
【问题描述】:

我在基类和派生类中都有一个方法。当我在派生类中的对象上调用此方法时,它调用基类方法而不是派生类方法。这是我的代码:

人.h

class Person
{
...
public:
...
    virtual void coutPerson();
};

Person.cpp

void Person::coutPerson() {
    cout << name << endl;
    birthday.coutDate();
    phoneNumber.coutPhoneNumber();
    cout << city << ", " << state << endl;
}

学生.h

class Student : public Person
{
...
public:
...
    virtual void coutPerson();
};

学生.cpp

void Student::coutPerson() {
    cout << "DEBUG: Student::coutPerson()" << endl;
    //Person::coutPerson();
    cout << "Dorm Room: " << this->dorm << " " << this->dormRoom << endl;
}

对象创建于:addPerson&lt;Student&gt;(personVector); 创建对象时,它被创建为学生,因为它调用学生构造函数。 方法调用于:personVector[num-1].coutPerson(); Student 对象是被告知 coutPerson 的对象,因为它显示了我在创建 Student 对象时提供的信息。

template<typename T> void addPerson(vector<Person> &personVector) {
    T p;
    personVector.push_back(p);
}

当在 Student 对象上调用 coutPerson() 方法时,它只会计算姓名、生日、电话号码以及城市和州。这段代码有什么问题?它应该调用 Student coutMethod...

谢谢!

【问题讨论】:

  • 呼叫站点在哪里?调用站点使用什么语法?
  • 确保您是通过指针或引用调用方法,而不是通过实际对象,除非对象的类型为Student不是类型为@987654329 @
  • 能否请您出示调用coutPerson()的代码?我很确定问题就在那里。
  • addPerson 是什么? personVector 是什么?
  • 调用 coutPerson 的代码可能不是问题。我创建了一个名为 studentName 的 Student,等等......它会输出“studentName”等......没有其他学生特定的值。

标签: c++ inheritance virtual


【解决方案1】:

您可能在某个时候将Student 对象复制到Person 对象,从而导致Object Slicing Problem。例如,您可能将它们存储在vector&lt;Person&gt; 中。您需要使用指针或引用而不是复制对象。

要解释为什么会出现这个问题,您必须意识到向量不会存储您在push_back 中传递给它的实际对象,它存储对象的副本。当您将 Student 复制到 Person 时,副本不再是 Student

【讨论】:

    【解决方案2】:

    您的 personVector 包含 Person 对象。不是对Person 对象的引用,而是实际的Person 对象。当您“将您的 Student 对象放入向量中”时,真正发生的是向量构造了一个 new Person 对象,该对象使用您提供的 Student 对象进行复制初始化也就是说,它创建了Student 对象的Person 部分的副本。这种行为也称为“切片”。

    由于向量中没有Student 对象,而只有Person 对象,因此在其上调用coutPerson 调用Person::coutPerson,而不是Student::coutPerson 也就不足为奇了。

    如果你想要多态行为,你必须在容器中存储指针(最好是像shared_ptrunique_ptr 这样的智能指针)。但是请注意,您在函数中构造的对象 p 在返回时会被销毁,因此要使对象存活(因此您可以拥有指向它的指针),您必须使用 new 分配它。

    【讨论】:

    • 为我工作。我有一个 BaseClass 对象数组 (BaseClass*),其中项目被分配给派生类对象实例。因此,即使我的基类函数是虚拟的,并且派生的函数明显覆盖它们,运行时多态性也不起作用。所以不得不将我的 BaseClass 对象数组更改为 BaseClass 对象指针数组(BaseClass**)并分别定义对象。我现在确实必须关心对象的生命周期,以保持它们在数组中的引用有效。一些对象使用 new 定义,而其他对象使用指向静态派生对象的指针分配。
    【解决方案3】:

    功能很好。您要么从Person 类型的对象调用coutPerson,要么从Person 的构造函数/析构函数内部调用它(感谢@celtschk)。
    您应该通过 pointerreference 调用 Person 类型的对象。这就是你获得多态性的方式。

    【讨论】:

    • 或参考-关键区别。
    • 很好,但你怎么知道的?
    • 我猜 10 次中有 9 次甚至没有看到问题所在的代码。
    • @Alex:不知道,还能是什么?
    • @AssafLevy:从基类的构造函数或析构函数调用函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 2016-07-12
    • 2013-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多