【问题标题】:Calling a derived virtual function调用派生的虚函数
【发布时间】:2013-12-04 10:35:36
【问题描述】:

我对 C++ 还很陌生,继承让我陷入了困境。 我知道这在 C# 中有效,因为我一直在使用 Base.();

我希望能够调用从 Entity 派生的 PlayerCharacter 向量数组。 目前我调用它时,它只调用Entity的更新方法。

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# 不同),因此您需要显式标识基类才能访问基类成员。
  • 你确定是Entity::Update被调用的吗?
  • 天哪,你正在将一个指向临时变量的指针推入向量中!将您的 push_back 行替换为:list.push_back( new PlayerCharacter() ); 并记住 - 您需要 delete 向量中的项目以避免内存泄漏。另外,list 是 STL 中的一个类名,因此称为 vector 的实例,我可以建议 vec 吗?
  • list.push_back(&amp;PlayerCharacter()); 正在将一个指针推送到一个立即被销毁的临时对象,因此向量中的指针立即无效。
  • 可能是一个愚蠢的问题,但从该代码示例中,我看不出您如何判断实际执行的是哪个方法。在这两种情况下,您都在分配一个局部变量,您使用 ++ 或 --,然后立即丢弃它。您如何观察结果?

标签: c++ function inheritance vector


【解决方案1】:

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

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

还可以跟踪调用了哪个函数,您可以使用调试器或从每个更新函数在控制台中打印一些内容。

【讨论】:

  • 我愿意,是的,这就是为什么我有 int a = 0;一个++;所以调试器运行过了那行代码,我可以把它捡起来。感谢您的提示:)
  • 实际上这似乎已经解决了我的惊讶!非常感谢:)
  • @user3065340 如果它解决了您的问题,请不要忘记将回复标记为您问题的答案:)
  • @user1158692 :) ,我认为它之所以调用它是因为基类中的 vtable 仍然存在,但它可能发生从崩溃到内存损坏的任何事情,这就是它被称为 ub 的原因。
【解决方案2】:

这个作品: 虽然变化很少: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();
    }
}

【讨论】:

  • 两个 cmets 和一个答案指出了OP在他们的push_back声明中犯的错误,但你已经复制了它!我建议你在得到一些当之无愧的反对票之前修复它!
  • 我在 main 中创建了 PlayerCharacter 对象,并将对象的地址传递给 List。由于列表需要实体指针,所以实际上基类实体指针指向派生类对象 PlayerCharacter。现在,当我们在 list[0] 上调用更新方法时,即在基类指针上,由于运行时多态性,它会调用派生类方法。
  • @user1158692 - 我不介意你的反对意见。我花了一些时间来构建和运行程序,同时你们发布了一个答案。我肯定会赞成你的回答。 P.S : 不是在如此拼命地获得声誉积分的比赛中
  • 诚然,您的程序 不会 具有与 OP 相同的 UB 问题,因为您正在传递命名对象的地址,并且向量和对象存在于相同的范围(如果 OP 正在阅读)- 可能不值得投反对票。
猜你喜欢
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-19
  • 2020-09-29
  • 2020-01-04
  • 2011-09-27
相关资源
最近更新 更多