【问题标题】:Storing a child-class pointer in a map of parent-class pointer将子类指针存储在父类指针映射中
【发布时间】:2017-04-18 03:00:20
【问题描述】:

假设我有一个名为Libitem 的父类和一个名为Book 的子类。如果我将Book 的指针存储在Libitem 的指针映射中,当我再次尝试访问它时,我会得到Book 的指针吗?像这样:

std::map<int, Libitem*> catalog;
Libitem* b = new Book();
catalog[1] = b;
Libitem* old_book = catalog[1]; //would old_book be a Book or a Libitem? In other word would it 
                               //have all the function of a Book class?

【问题讨论】:

  • 请搜索并阅读downcasting。

标签: c++ pointers polymorphism


【解决方案1】:

你正在像这样检索你的对象:

Libitem* old_book = catalog[1];

这样,编译器只知道您有一个名为old_book 的变量,类型为指向Libitem。如果您自己单独阅读该特定行,您会注意到唯一的这是您和编译器在那一刻拥有的唯一信息。当你自己阅读这行代码的那一刻就是编译时间。看代码就知道什么了。

当程序实际运行时,该变量可能指向Book 类型的对象。但这只有在程序运行时才知道,因此 runtime。

名称查找发生在 C++ 的编译时。当您像这样在对象上调用函数时:

// Type of an_object is a_struct
a_struct an_object;

an_object.member_function();

编译器将查看a_struct 中可用的函数。由于编译器在变量已声明的结构中查找该名称,因此名称实际上是在编译时解析的。


让我们回到你的案例。你有一个指向Libitem 的指针。如果您尝试使用箭头访问其中的某些内容:

old_book->something

为了解析something 是什么,编译器将在Libitem 内部查找它,因为old_book 的类型是指向Libitem 的指针。即使指针指向子类的实例,编译器唯一知道肯定的是指向的对象的实际类型至少是Libitem。

现在,人类比编译器知道的更多。您知道指针old_book 指向Book 类的一个实例。您想访问Book 的成员。

为此,您必须明确告诉编译器您要使用来自子类的成员。为此,您的变量必须是Book 类型,因此编译器将在适当的类中查找。为此,您可以将变量转换为另一种类型。由于您将变量转换为层次结构中较低的类,因此称为向下转换。在这种情况下,我们可以使用的类型转换是 dynamic_cast,它会在运行时查看指针所指向的实例的实际类型:

if (Book* the_old_book = dynamic_cast<Book*>(old_book)) {
    // We can use the_old_book here, which his type is Book!
} else {
    // The cast failed, the real for of the variable is not Book,
    // and the_old_book points to nullptr
}

如您所见,我们创建了一个名为the_old_book 的新指针,它由强制转换的结果初始化。如果old_book 指向的实例的真实类型确实不是Book,则强制转换将失败并返回nullptr。由于这发生在运行时,我们必须使用运行时分支 if 来验证我们的新变量。如果转换失败,执行的块将是 else 块。

【讨论】:

  • 好吧,整个施法机制会很有帮助......但只是为了确保,存储在 catalog[1] 中的指针在技术上总是一个孩子,对吧?换句话说,如果我将存储在catalog[1] 中的指针传递给另一个向量或映射,我是否能够从新集合中检索它并仍然能够将其动态转换为Book?
  • 是的。实际实例的类型不会改变。您可以创建、复制和转换指针。如果最终指针指向您分配对象的同一位置,您将能够向下转换它。
【解决方案2】:

它就像任何其他多态指针:Libitem 的功能,但在方法中具有 Book 的任何虚拟覆盖。

但是:您将无法访问Book 的非虚拟方法,无论它是与Libitem 中的任何方法具有完全不同名称的函数/方法,方法名称相同但参数签名不同在Libitem 中,或非虚拟 与Libitem 中的方法具有相同名称和签名的情况。

当然,如果你是一个强壮的人,你可以沮丧(正如@SomeProgrammerDude 指出的那样)。

【讨论】:

  • 等一下,只能访问 Book 的虚拟覆盖吗?所有不是虚拟但属于Book(并且不是从Libitem 继承)的内容都将无法访问?
  • 任何不是从Libitem继承的都是不可访问的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-18
  • 2015-05-03
  • 1970-01-01
  • 2011-09-26
相关资源
最近更新 更多