C ++虚拟虚空与非虚拟虚空

时间:2018-07-24 12:00:46

标签: c++ c++11

我对虚函数感到困惑。有人告诉我,父类中的virtual表示我可以在子类中覆盖它。但是,如果我在父类中省略了virtual,则仍然可以覆盖它。

#include <iostream>
using namespace std;

class Enemy{
  public:
    //if I remove virtual, it still gets overriden in child class
  virtual void attack(){ 

    cout << "Attack Enemy!" << endl;
  }
};


class Minion : public Enemy {
  public:
  void attack(){
    cout << "Attack Minon!" << endl;
  }
};
int main() {
  Minion m;
  m.attack();
}

3 个答案:

答案 0 :(得分:0)

您没有覆盖它,只是添加了具有相同签名的另一个方法。

Enemy* enemy = new Minion();

enemy->attack();

delete enemy;

如果 this 调用Minion中的代码,则说明操作正确。如果它从Enemy调用代码,则说明您做错了。您将需要virtual来正确完成操作。

答案 1 :(得分:0)

如果函数是虚函数,则在运行时通过vtable将调用动态分派给派生类型提供的实现,否则,编译器将在编译时查看对象并选择静态类型的类方法。如果您有一个指向基类的指针,则意味着如果该函数不是虚拟的,则使用基类实现:

Enemy *e = new Minion(); e->attack();

将打印“攻击敌人!”如果attack不是虚拟的。使用虚函数时,编译器将插入一些逻辑以在运行时查找正确的实现,并且当执行e->attack()时,在对象指针的vtable中查找由{{1}指向的实现},发现e覆盖了Minion,因此打印了“ Attack Minion!”。

如果您想强制派生类重写基类方法,则还可以通过使用

使该函数完全虚拟化

attack

答案 2 :(得分:0)

您可以覆盖有问题的方法,并在理想情况下使用override关键字进行声明,以使编译器在不覆盖任何内容时进行投诉。

class Enemy {
  public:
    virtual ~Enemy() = default; /* Don't forget... or non-virtual protected. */

    virtual void attack() {}
};

class Minion : public Enemy {
  public:
    void attack() override {}
};

您的困惑可能源于您可以很好地遮盖基类方法的事实。

class Enemy {
  public:
    virtual ~Enemy() = default;
    void attack() {}
};

class Minion : public Enemy {
  public:
    void attack() {}
};

这不仅会做一些不同的事情,而且还会给命名异常带来麻烦,这会使读者感到困惑:在类层次结构的上下文中具有相同签名的相等成员函数名称不可避免地与重写方法相关联