C++:创建抽象类和抽象方法,并在子类中重写该方法

19

如何在C++中创建一个带有一些抽象方法的抽象类,我想在子类中重写这些方法?
头文件应该是什么样子?如果有.cpp文件,那它应该是什么样子?

在Java中会是这样:

abstract class GameObject
{
    public abstract void update();
    public abstract void paint(Graphics g);
}

class Player extends GameObject
{
    @Override
    public void update()
    {
         // ...
    }

    @Override
    public void paint(Graphics g)
    {
         // ...
    }

}

// In my game loop:
List<GameObject> objects = new ArrayList<GameObject>();
for (int i = 0; i < objects.size(); i++)
{
    objects.get(i).update();
}
for (int i = 0; i < objects.size(); i++)
{
    objects.get(i).paint(g);
}

对我来说,将这段代码翻译成C++就足够了。

编辑:

我创建了代码,但当我尝试迭代对象时,会出现以下错误:

Game.cpp:17: error: cannot allocate an object of abstract type ‘GameObject’
GameObject.h:13: note:   because the following virtual functions are pure within ‘GameObject’:
GameObject.h:18: note:         virtual void GameObject::Update()
GameObject.h:19: note:         virtual void GameObject::Render(SDL_Surface*)
Game.cpp:17: error: cannot allocate an object of abstract type ‘GameObject’
GameObject.h:13: note:   since type ‘GameObject’ has pure virtual functions
Game.cpp:17: error: cannot declare variable ‘go’ to be of abstract type ‘GameObject’
GameObject.h:13: note:   since type ‘GameObject’ has pure virtual functions

使用以下代码:

vector<GameObject> gameObjects;

for (int i = 0; i < gameObjects.size(); i++) {
    GameObject go = (GameObject) gameObjects.at(i);
    go.Update();
}

你的“在我的游戏循环中”的代码最多只能算不完整。 objects是什么?如果您还没有自己的编程知识,我强烈建议从 The Definitive C++ Book Guide and List 中获取一本入门书籍。 - James McNellis
您还可以参考Herb Sutter的文章《Virtuality》(http://www.gotw.ca/publications/mill18.htm),该文章讨论了在C++中使用虚函数和继承时的许多最佳实践。 - James McNellis
3个回答

26

在Java中,默认情况下所有方法都是virtual的,除非你将它们声明为final。而在C++中则相反:您需要明确声明您的方法为virtual。如果要使它们成为纯虚拟的,您需要将它们“初始化”为0 :-) 如果您的类中有一个纯虚拟的方法,则它会自动成为抽象的——没有显式的关键字可用。

在C++中,您应该(几乎)总是将基类的析构函数定义为virtual,以避免棘手的资源泄漏。因此,在下面的示例中,我添加了这个:

// GameObject.h

class GameObject
{
public:
    virtual void update() = 0;
    virtual void paint(Graphics g) = 0;
    virtual ~GameObject() {}
}

// Player.h
#include "GameObject.h"

class Player: public GameObject
{
public:
    void update();

    void paint(Graphics g);
}

// Player.cpp
#include "Player.h"

void Player::update()
{
     // ...
}

void Player::paint(Graphics g)
{
     // ...
}

2
@Martijn,你不能有一个vector<GameObject>,因为它会按值存储其元素,但是GameObject是抽象的,无法有实例。你需要一个vector<GameObject*>或者更好的是一个vector<shared_ptr<GameObject*>>来存储多态对象。另请参见James McNellis答案的评论。 - Péter Török
为什么在GameObject.h中需要声明方法,如果它们已经被声明了? - HasaDev
自C++11起,您还应该使用override说明符来指定虚函数覆盖。参见:https://en.cppreference.com/w/cpp/language/override。 - damb

7
基类中的成员函数需要声明为 virtual 。在Java中,成员函数默认情况下是虚拟的;而在C ++中不是。
class GameObject
{
public:
    virtual void update() = 0;
    virtual void paint(Graphics g) = 0;
}

virtual关键字用于声明一个虚函数,而= 0则用于声明一个纯虚函数。这个类是抽象类,因为它至少有一个没有具体实现的虚函数。

在你的派生类中:

class Player : public GameObject
{
public:
    void update() { }          // overrides void GameObject::update()
    void paint(Graphics g) { } // overrides void GameObject::paint(Graphics)
}

如果在基类中声明一个成员函数为虚函数,那么在任何派生类中它都会自动成为虚函数(你可以在派生类的声明中加上virtual,但这是可选的)。


我能否仅调用update();来更新GameObject向量中的每个元素? - Martijn Courteaux
不行。你需要一个 GameObject* 的向量或类似 shared_ptr 或 auto_ptr 的相关类。 - Puppy
是的,但这是由于“GameObject”是抽象的这一事实所暗示的。 - James McNellis

4

在C++中,您可在函数前使用关键字“virtual”,并将=0;赋值到它们中。例如:

class GameObject {
public:
    virtual void update()=0;
    virtual void paint(Graphics g)=0; 

}

拥有一个虚方法,并将0分配给它,会自动使您的类成为抽象类。

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