调用派生类的虚函数

3

我对C++还比较新,继承让我很困惑。 我知道在C#中这很好用,因为我总是使用Base.();

我希望能够调用一个PlayerCharacter的向量数组,它派生自Entity。 目前当我调用它时,它只调用Entity的update方法。

int main()
{
vector<Entity*> list;
list.push_back(&PlayerCharacter());

   for(int i = 0; i < list.size(); i++)
   {
   list[0]->Update();
   }
}

class Entity
{
public:
    Entity(void);
   ~Entity(void);
    int hitpoints;
    virtual void Update(void);
};
void Entity::Update(void)
{
    int a = 0;
    a++;
}
class PlayerCharacter : public Entity
{
public:
    PlayerCharacter(void);
    ~PlayerCharacter(void);
    bool Move();
    void Update() override;
};
void PlayerCharacter::Update(void)
{
    int a = 0;
    a--;
}

要调用基类(我认为您在询问的)请在PlayerCharacter::Update()内使用Entity::Update()。在C++中,一个类可以有几个非抽象的基类(不像C#),因此需要显式标识基类来访问基类成员。 - Grimm The Opiner
1
你确定正在调用的是 Entity::Update 吗? - Chris Mantle
6
天啊,你正在将指向临时变量的指针放入向量中!请用以下代码替换你的push_back语句:list.push_back(new PlayerCharacter()); 记住,你需要删除向量中的项目以避免内存泄漏。此外,list是STL中的一个类名,所以为了避免混淆,可以将vector的实例命名为其他名称,比如我建议用vec - Grimm The Opiner
list.push_back(&PlayerCharacter()); 将一个指向即将被销毁的临时对象的指针推入列表中,因此向量中的指针立即变为无效。 - Michael Burr
可能是一个愚蠢的问题,但从那个代码示例中我看不出你如何确定哪个方法实际上正在执行。在这两种情况下,您都分配了一个本地变量,然后++或--,然后立即丢弃它。你是如何观察结果的? - harmic
@harmic 是个好问题 - 他使用这些行作为断点停放区。 - Grimm The Opiner
2个回答

4

list.push_back(&PlayerCharacter()); 我认为这是您代码中的未定义行为。

在您的情况下,您应该像这样在堆上分配数据:list.push_back( new PlayerCharacter() ); 否则,如果您这样做&PlayerCharacter(),那么PlayerCharacter变量将立即被销毁,并且列表内的指针将指向垃圾字节。

另外,要跟踪哪个函数被调用,您可以使用调试器或从每个Update函数中在控制台打印一些内容。


我是这样做的,是的,这就是为什么我有int a = 0; a++; 这样调试器就可以跳过那行代码,然后我就可以接着进行。谢谢你的提示 :) - Anthony
实际上这似乎已经出乎我的意料解决了!非常感谢 :) - Anthony
@user3065340 如果这个回复解决了你的问题,请不要忘记将其标记为答案 :) - Raxvan
1
@user1158692 :),我认为它被调用是因为基类的虚函数表仍然存在,但可能会发生从崩溃到内存损坏的任何事情,这就是为什么它被称为未定义行为。 - Raxvan

-1

这个方法可行: 虽然有几个更改:1)您不需要放置 Override 2)一旦声明构造函数和析构函数的定义3)创建了派生类的对象并将其传递到列表中。

输出为:在PlayerCharacter内部

如果要调用基类更新方法,请删除 volatile 关键字。或者使用指向基类对象的基类指针。

class Entity
{
public:
    Entity();
    ~Entity();
    int hitpoints;
    virtual void Update(void);
};

Entity::Entity()
{
}
Entity::~Entity()
{
}
void Entity::Update(void)
{
    std::cout << " Inside Entity" <<std::endl;
    int a = 0;
    a++;
}
class PlayerCharacter : public Entity
{
public:
    PlayerCharacter();
    ~PlayerCharacter();
    bool Move();
    void Update();
};
void PlayerCharacter::Update(void)
{
    std::cout << " Inside PlayerCharacter" <<std::endl;
    int a = 0;
    a--;
}

PlayerCharacter::PlayerCharacter()
{

}

PlayerCharacter::~PlayerCharacter()
{    

}
int main()
{
    vector<Entity*> list;
    PlayerCharacter ObjPlayerCharacter;
    list.push_back(&ObjPlayerCharacter );

    for(unsigned int i = 0; i < list.size(); i++)
    {
        list[0]->Update();
    }
}

已经有两个评论和一个答案指出了原帖中push_back语句的错误,然而你却复制了它!我建议你在遭受应有的负评之前先修复它! - Grimm The Opiner
我在主函数中创建了PlayerCharacter对象,并将该对象的地址传递给List。由于列表期望实体指针,因此基类实体指针实际上指向派生类对象PlayerCharacter。现在,当我们在列表[0],即基类指针上调用更新方法时,由于运行时多态性,它会调用派生类方法。 - Biraj Borah
@user1158692 - 我并不在意你们的负评。我花了一些时间来构建和运行程序,与此同时你们已经发布了答案。我肯定会给你的回答点赞。另外,我并不急于追求声望分数的竞赛。 - Biraj Borah
毫不否认,您的程序与OP的存在UB问题不同,因为您正在传递命名对象的地址,而向量和对象存在于相同的作用域中(如果OP正在阅读)- 可能不值得被投票降低。 - Grimm The Opiner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接