c++ - 在库开发中使用派生方法
问题描述
我正在编写一个小型游戏引擎(用作库),同时将自己重新读入 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()。我发现其他关于多态性的(相对)类似问题的帖子,但那里的答案总是代表我的预期行为。所以我的问题是:为什么这不能像我想要的那样工作的可能性是什么,或者更准确地说:这可能是使用代码作为共享库的结果吗?也许我找不到的代码中有错误......我希望并认为,我给你的代码应该足够了。我怀疑,这是别的什么。但是,如果问题一定出在其他地方,我会很高兴有一些潜在的错误,这可能会导致这种情况。
解决方案
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
}
推荐阅读
- mysql - 模型的 Laravel“加载”关系函数在 SQL 中产生“未准备”语句
- javascript - 如何在不更改模板的情况下交换显示的 html 对象的顺序?
- flutter - Flutter,setState时热不调用StreamBuilder
- amazon-web-services - AWS IoT:何时在 Shadow 上使用事物属性
- c++ - 三路比较和 constexpr 函数模板:哪个编译器是对的?
- c# - 如何用另一个单词替换以某个单词开头的路径目录?
- tensorflow - Conv2D 层的 VALID 填充问题
- android - 将 Android 应用 google 登录迁移到另一个 GCP 项目
- vb.net - 在 PowerPoint 中的句子中超链接一个单词
- android - Get Api Works 在模拟器中但在真实设备 Flutter 中不可用