填充子类的基类向量不起作用

时间:2018-12-19 16:21:53

标签: c++ class inheritance polymorphism stdvector

我正在尝试使用具有相同基类的不同子类指针的向量。该向量设置为基类指针,但是添加到该向量的任何内容都无法获得其子类的全部功能。 在错误日志中可以看到它被视为基类,因此无法获得扩展功能。

我查看了很多问题,人们说要按照我的方式去做,但是出于某种原因,它是行不通的。

该代码位于公共仓库中。

https://repl.it/@cubingminer8/inheritance-with-vectors-testing

任何帮助将不胜感激!

edit:好的,所以我将在c ++ sdl2游戏引擎中将其用于sprite组系统。将有一个基本的Sprite类,其中包含一些基本的东西,例如render和move,而我需要的任何Sprite都是它们自己的继承自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.
}

2 个答案:

答案 0 :(得分:4)

通常,这是通过虚拟功能实现的。在给定的情况下,它应该是一个虚拟的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;

作为旁注,建议您查看smart pointers而不是行指针,从而避免手动存储管理。

一个好的开始是:

#include <memory>

std::vector<std::unique_ptr<Base>> List;
List.emplace_back(std::make_unique<Sub>());

答案 1 :(得分:2)

因此,您希望它能够正常工作:

// 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. 编译器编译时应该知道版本1是正确的,而版本2是错误的。不幸的是,这通常是不可能的,因为编译器无法跟踪对象指针指向数组的哪个插槽。因此,必须将其消除。
  2. 运行时系统应在运行时检测到错误。这是一种可能的方法,但不是C ++采取的方法。 C ++是一种静态类型语言。动态类型的语言可以处理这种情况。如果您要使用动态类型的语言,请尝试例如Python。
  3. 编译器不应尝试检测任何东西,运行时系统也不应尝试检测任何东西,但是无论如何都要继续执行该操作,并使其产生错误的结果或崩溃。这也是一种可能的方法,但是任何现代高级编程语言都不会采用。 C ++和其他现代语言是类型。可以使用reinterpret_cast之类的方法来绕过C ++的类型系统,但这非常危险,因此不建议使用。
  4. 编译器应将两个版本均视为错误。这就是C ++的作用。

正如其他人提到的那样,扩展类功能的(唯一)正确方法是通过虚函数。这需要进行一些计划。尽管不需要知道 派生类将如何实现它们,但基数至少应声明需要进行哪些操作。