我试图拥有一个具有共同基类的不同子类指针的向量。向量设置为基类指针,但添加到向量的任何内容都无法获得其是子类的完整功能。可以在错误日志中看到它被视为基类,因此无法获得扩展功能。
我看了很多问题,人们说要按照我的方式做,但是无论出于何种原因,它都行不通。
代码在公共回购上:
https://repl.it/@cubingminer8/inheritance-with-vectors-testing
任何帮助将不胜感激!
编辑:好的,所以我将在C SDL2游戏引擎中使用它用于Sprite组系统。将会有一个基本的精灵级别具有一些基本的东西,例如渲染和移动,而我需要的任何精灵都将是他们自己的班级,它们从Sprite继承,它们将具有自己的独特行为,因此虚拟功能将是不切实际的。将会有一个精灵组对象,可以存储从Sprite继承的对象。因此,它们都可以立即渲染。
如果您曾经使用过 pygame ,那么它几乎与Sprite和SpriteGroup系统相同。https://www.pygame.org/docs/tut/spriteintro.html
#include <iostream>
#include <vector>
class Base {
public:
char A = 'A';
};
class Sub : public Base {
public:
char B = 'B';
};
class Sub2 : public Base {
public:
char C = 'C';
};
int main() {
std::vector<Base*> List;
List.push_back(new Sub());
List.push_back(new Sub2());
std::cout << List[0]->B << std::endl; // it should be able to print B
std::cout << List[1]->C << std::endl; // but it is being set as a base class and
// not getting the functionality of the subclass it is.
}
通常,这是通过虚拟函数实现的。在给定的情况下,它应该是一个虚拟getter函数,它返回每个类的char
成员。
class Base {
char A = 'A';
public:
virtual char getChar()const /*noexcept*/ { return A; }
virtual Base () = default;
};
class Sub : public Base {
char B = 'B';
public:
char getChar()const /*noexcept*/ override { return B; }
};
class Sub2 : public Base {
char C = 'C';
public:
char getChar()const /*noexcept*/ override { return C; }
};
现在在主机
std::cout << List[0]->getChar() << std::endl;
作为旁注,我建议您看看智能指针,而不是行指针,您可以避免手动记忆管理。
一个好的开始是:
#include <memory>
std::vector<std::unique_ptr<Base>> List;
List.emplace_back(std::make_unique<Sub>());
,所以您希望它能起作用:
// your code version 1
std::cout<< List[0]->B << std::endl; //it should be able to print B
std::cout<< List[1]->C << std::endl; //but it is being set as a base class
但是如果您写这篇文章应该会发生什么?
// your code version 2
std::cout<< List[0]->C << std::endl;
std::cout<< List[1]->B << std::endl;
List[0]
没有任何C
,List[1]
没有任何B
。您如何建议处理此代码?
有几种方法可以解决此问题。
- 编译器应该在编译时间中知道版本1是正确的,而版本2是错误的。不幸的是,这通常是不可能的,因为编译器无法跟踪对象指针在数组中的哪个插槽。因此必须驳回这一点。
- 运行时间系统应在运行时间上检测错误。这是一种可能的方法,而不是C 采用的方法。C 是A 静态键入语言。动态键入的语言可以处理这种情况。如果您想要动态键入的语言,请尝试例如python。
- 编译器不应试图检测任何内容,并且运行时系统也不应尝试检测任何内容,而是继续进行操作,然后让它产生错误的结果或崩溃。这也是一种可能的方法,但不是任何现代高级编程语言所采用的方法。C 和其他现代语言是键入。可以使用
reinterpret_cast
等来规避C 的类型系统,但这是非常危险的,不建议。 - 编译器应将两个版本都视为错误。这就是C 的作用。
正如其他人提到的那样,扩展类功能的(仅)正确的方法是通过虚拟函数。这需要提前一些计划。基础至少应声明需要哪个操作,尽管它不需要知道派生的类将如何实现它们。