首页 > 解决方案 > 在库开发中使用派生方法

问题描述

我正在编写一个小型游戏引擎(用作库),同时将自己重新读入 c++。我用 Java 编码已经好几年了,但似乎 c++ 处理多态性有点不同,我遇到了以下问题:

我有一个类GameObject,它代表游戏中任何类型对象的基本功能。所以这基本上被用作一个抽象类。我有几个对象,它们覆盖 GameObject 包括一个类Map。这些对象最终在游戏中使用。

所有这些都被编译成一个库并被游戏使用。

这是我使用的基本代码:gameobject.h:

class GameObject {
    public:
        void loadFromJson(nlohmann::json& json);
        void load();
    // [...] not relevant
}

游戏对象.cpp:

void GameObject::loadFromJson(nlohmann::json& json) {
    // [...] not relevant
    std::cout << "base-class function" << std::endl;
}

void GameObject::load() {
    // [...] not relevant
    this->loadFromJson(json);
}

地图.h:

class Map : public GameObject {
    public:
        void loadFromJson(nlohmann::json& json);
        // [...] not relevant
}

地图.cpp:

void Map::loadFromJson(nlohmann::json& json) {
    // [...] not relevant
    GameObject::loadFromJson(json);
    std::cout << "derived class function" << std::endl;
}

游戏内的主要内容:

int main() {
    Map* map = new Map(...);
    map->load();
}

我不确定makefile中的哪些参数是相关的,因此我只是粘贴了我使用的所有内容,包括应该不相关的库:makefile、gameengine(称为gct):

COMPARGS=-Wall -I$(INCLUDEPATH) -I$(LIBPATH) -I$(LIBPATHGLADINCLUDE) -std=c++17 -fsanitize=address -fPIC $(SDL_FLAGS) $(PKG_FLAGS) -lplibfnt -lSOIL -lstdc++fs -g

$(OUTPUTPATH)libgct.so: [...] gameobject [...] map
$(CC) -shared [...] gameobject [...] map -o $(OUTPUTPATH)libgct.so

gameobject: $(SRCPATH)gameobject.cpp $(INCLUDEPATHGCT)gameobject.h
$(CC) $(SRCPATH)gameobject.cpp -c -o gameobject $(COMPARGS)

map: $(SRCPATHMAP)map.cpp $(INCLUDEPATHGCTMAP)map.h
$(CC) $(SRCPATHMAP)map.cpp -c -o map $(COMPARGS)

生成文件,游戏:

COMPARGS=-Wall -std=c++17 -fsanitize=address -I$(LIBINCLUDE) -lgct -lplibfnt -lplibul $(SDL_FLAGS) $(PKG_FLAGS) -lSOIL -lstdc++fs -g

testgame: $(SRCPATH)main.cpp [...]
$(CC) $(SRCPATH)main.cpp [...] $(COMPARGS) -o testgame

现在我的预期行为将是输出:“基类函数”“派生类函数”

但我得到的是:“基类函数”

我已经遇到了在库中使用多态性的问题,loadFromJson() 在基类中是虚拟的。并将其与 GameObjects 数组一起使用(当时它与其他类和其他方法一起使用,但其背后的原理应该很清楚)。这导致了奇怪的错误,谷歌解释说这种多态性很慢,不应该在库中使用。我知道,这种多态性方式应该没有太大区别,但我没有得到任何错误。只是不是预期的行为,我觉得这应该可行。

然而,这是我能够解决的其他类和其他方法的不同问题。但是,如果我不能使用它,这会很烦人,因为我必须一遍又一遍地在派生类中重写 load()。我发现其他关于多态性的(相对)类似问题的帖子,但那里的答案总是代表我的预期行为。所以我的问题是:为什么这不能像我想要的那样工作的可能性是什么,或者更准确地说:这可能是使用代码作为共享库的结果吗?也许我找不到的代码中有错误......我希望并认为,我给你的代码应该足够了。我怀疑,这是别的什么。但是,如果问题一定出在其他地方,我会很高兴有一些潜在的错误,这可能会导致这种情况。

标签: c++gccpolymorphism

解决方案


virtual不同之处在于 Java 方法默认是虚拟的,c++ 方法不是,您需要使用关键字显式标记您想要虚拟的任何方法。

class GameObject {
    public:
        virtual void loadFromJson(nlohmann::json& json);
        void load();
    // [...] not relevant
}

标记派生方法是个好主意,override因此如果您的方法没有覆盖基类方法,编译器会引发错误:

class Map : public GameObject {
    public:
        void loadFromJson(nlohmann::json& json) override;
        // [...] not relevant
}

推荐阅读