C++ 错误消息:不允许抽象类类型为“X”的对象:纯虚拟“Y”没有重写器

C++ 错误消息:不允许抽象类类型为“X”的对象:纯虚拟“Y”没有重写器,c++,C++,敌人 敌方 class Enemy { int hp; public: Enemy(int); void setHP(int); int getHP(); virtual int attack() = 0; }; 收割者 Enemy::Enemy(int playerXP) { if (playerXP == 0) { hp = rand() % 5 + 1; } else if (playerXP > 0)

敌人

敌方

class Enemy
{
    int hp;
public:
    Enemy(int);
    void setHP(int);
    int getHP();
    virtual int attack() = 0;
};
收割者

Enemy::Enemy(int playerXP)
{
    if (playerXP == 0) {
        hp = rand() % 5 + 1;
    }
    else if (playerXP > 0) {
        hp = rand() % (playerXP * 5) + 1;
    }
}

void Enemy::setHP(int currentHP)
{
    hp = currentHP;
}

int Enemy::getHP()
{
    return hp;
}
收割者

#pragma once
#include "Enemy.h"

class Reaper : public Enemy
{
public:
    Reaper(int playerXP) : Enemy(playerXP)
    {   
    }

    int attack(int, int);
};
错误:

不允许抽象类类型为Reaper的对象: 纯虚拟功能敌人:攻击没有覆盖者

我的问题是。。为什么我会犯这个错误?我试图理解我为什么会得到这个问题,以及解决这个问题的任何可能的答案。

收割者是抽象的,因为它没有覆盖抽象的敌人::攻击方法,而是重载它。因此,您不能直接创建收割者的任何对象实例

当派生类希望重写基类的虚拟方法时,派生方法必须具有与其重写的基类方法相同的签名。这意味着它具有相同的返回类型,或者至少具有兼容的调用约定、参数列表和常量

收割者::攻击与敌人::攻击具有不同的参数列表。这就是为什么收割者::攻击是重载而不是覆盖

在C++11及更高版本中,您可以并且应该使用新的标记Reaper::attack,例如:

这样,编译器将采取额外的步骤来验证是否确实存在兼容的基方法,如果没有找到,那么它将发出更有意义的错误消息。例如,使用覆盖时会产生以下错误,如上所示:

class Reaper : public Enemy
{
public:
    ...    
    int attack(int, int) override;
};
收割者是抽象的,因为它不是覆盖抽象的敌人::攻击方法,而是重载它。因此,您不能直接创建收割者的任何对象实例

当派生类希望重写基类的虚拟方法时,派生方法必须具有与其重写的基类方法相同的签名。这意味着它具有相同的返回类型,或者至少具有兼容的调用约定、参数列表和常量

收割者::攻击与敌人::攻击具有不同的参数列表。这就是为什么收割者::攻击是重载而不是覆盖

在C++11及更高版本中,您可以并且应该使用新的标记Reaper::attack,例如:

这样,编译器将采取额外的步骤来验证是否确实存在兼容的基方法,如果没有找到,那么它将发出更有意义的错误消息。例如,使用覆盖时会产生以下错误,如上所示:

class Reaper : public Enemy
{
public:
    ...    
    int attack(int, int) override;
};

编译器没有意识到您想要重写基类中的攻击函数。它将int-attackint和int-attackint,int视为两个不同的函数,因为它们具有不同的类型签名。结果是您的Reaper类有两个函数,其中一个是纯虚函数。使用override关键字有助于避免这些错误,尽管它仅在C++11及更高版本中可用。

编译器没有意识到您想要覆盖基类中的攻击函数。它将int-attackint和int-attackint,int视为两个不同的函数,因为它们具有不同的类型签名。结果是您的Reaper类有两个函数,其中一个是纯虚函数。使用override关键字有助于避免这些错误,尽管它仅在C++11及更高版本中可用。

如果您希望某个函数重写另一个函数,可以使用override关键字确保它实际上是重写的。编译器将提供更好的错误消息,并且某些IDE将在您键入时显示潜在的编译错误。如果您希望某个函数重写另一个函数,可以使用override关键字确保它实际上被重写。编译器将提供更好的错误消息,一些IDE将在您键入时显示潜在的编译错误。我如何执行重写攻击函数?@BrandonTorrens您必须从Reaper::attack中删除额外的int参数,以便它与敌军::attack完全匹配。这意味着您必须找到另一种方法将所需的pa和php值传递给Reaper对象。好的,先生,感谢您的帮助,它成功了,我也能够改进逻辑,多亏了您,非常感谢。@RemyleBeau我该如何做一个覆盖攻击函数?@BrandonTorrens您必须从Reaper::attack中删除额外的int参数,以便它与敌军::attack完全匹配。这意味着您必须找到另一种方法将所需的pa和php值传递给收割者对象。好的先生,感谢您的帮助,它成功了,我也能够改进逻辑,感谢您,非常感谢。@RemyLebeau prog.cpp:41:9: error: ‘int Reaper::attack(int, int)’ marked ‘override’, but does not override int attack(int, int) override; ^~~~~~ prog.cpp: In function ‘int main()’: prog.cpp:57:9: error: cannot declare variable ‘r’ to be of abstract type ‘Reaper’ Reaper r(0); ^ prog.cpp:34:7: note: because the following virtual functions are pure within ‘Reaper’: class Reaper : public Enemy ^~~~~~ prog.cpp:11:17: note: virtual int Enemy::attack() virtual int attack() = 0; ^~~~~~