在父类指针的映射中存储子类指针

时间:2017-04-18 03:00:21

标签: c++ pointers polymorphism

所以说我有一个名为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?

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:2)

您正在检索您的对象:

Libitem* old_book = catalog[1];

有了这个,编译器只知道你有一个名为old_book的变量指向Libitem 的变量。如果你自己只阅读那条特定的行,你会发现只有这是你和编译器当时唯一的信息。你自己读这行的那一刻就是编译时间。通过阅读代码可以了解的内容。

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

名称查找在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块。