【问题标题】:How to store a pointer to SubClass object in a BaseClass pointer array?如何将指向子类对象的指针存储在 BaseClass 指针数组中?
【发布时间】:2019-12-18 15:34:41
【问题描述】:

我正在尝试创建一个存储 SubClass 对象的 BaseClass 数组。以下是我用来执行此操作的以下步骤:

  1. 我创建了一个 BaseClass 数组。
  2. 我创建了一个新的 SubClass 对象以存储在数组中。
  3. 我调用数组中该对象的 printSelf() 函数。
  4. 该方法错误地调用了 BaseClass 函数,而不是 SubClass 函数。

这里的错误是BaseClass数组中存储的对象是BaseClass对象。我需要它以便 BaseClass 数组存储一个 SubClass 类型的对象。

问题的设计使得如果有多个子类(即 SubClassA、SubClassB、SubClassC...),它们都将存储在一个数组中。

我在 StackOverFlow 上尝试了各种其他解决方案。到目前为止,还没有一个解决方案来解释为什么创建 SubClass 对象不会将其类类型正确地存储在 BaseClass 数组中。

class BaseClass {
    public: void printSelf() { cout << "This element is a BaseClass." << endl; };
};

class SubClass : public BaseClass {
    public: void printSelf() { cout << "This element is a SubClass." << endl; };
};

class House {
    public: House();
    private: BaseClass* subClassArray[1];
};

House::House() {
    subClassArray[0] = new SubClass;
    subClassArray[0]->printSelf();
}

int main() {
    House houseMain;
}

我希望输出是“这个元素是一个子类”。

相反,我收到的输出是“这个元素是一个 BaseClass。”

【问题讨论】:

  • C++ 不能以这种方式工作。这称为“对象切片”。这就是对象在 Java 中的工作方式,但 C++ 不是 Java。有关更多信息,请参阅重复的问题。您将派生类,子类,数组中的值分配给基类。这会切掉派生类,将基类留在数组中。如果您只是将一个普通的派生类对象分配给一个普通的基类对象,也会发生同样的事情。
  • What is object slicing?的可能重复

标签: c++ arrays parent-child subclass base-class


【解决方案1】:

您需要将printSelf 声明为虚拟。此外,您几乎肯定希望在您的类中添加一个虚拟析构函数。

class BaseClass {
    public: virtual void printSelf() const { cout << "This element is a BaseClass." << endl; };
            ////// <- must           ///// <- recommended
            virtual ~BaseClass() = default; // <-- HIGHLY recommended
};

class SubClass : public BaseClass {
    public: void printSelf() const override { cout << "This element is a SubClass." << endl; };
                                   //////// <- recommended
};

下面这行有两次问题。

private: BaseClass* subClassArray[1];

首先,它使用原始的 C 样式指针。其次,它使用原始的 C 样式数组。在当今的 C++ 开发中不推荐两者。您想了解智能指针,std::vectorstd::array

不要在此处使用任何类型转换,这是不可选项。

【讨论】:

  • 与我的教授交谈后,这是确定的解决方案。显然,数组格式在赋值时出错,但正在测试的是虚拟功能。
【解决方案2】:

问题在于您隐藏了printSelf 方法,而不是覆盖它。因此,当您有一个指向基类类型的指针时,将使用基类版本的printSelf

有两种方法可以解决这个问题,将subClassArray[0] 转换为子类类型(不推荐,除非您不拥有基类),或者将printSelf 标记为虚拟并在子类中覆盖它。

【讨论】:

  • "将 subClassArray[0] 转换为子类类型" 在向毫无准备的初学者推荐狂野和危险的东西时,请格外小心。
猜你喜欢
  • 2021-05-20
  • 1970-01-01
  • 2016-12-23
  • 2023-02-09
  • 2014-01-26
  • 1970-01-01
  • 2016-03-26
  • 2014-04-21
  • 1970-01-01
相关资源
最近更新 更多