2017-04-18 44 views
2

的存储的子类指针所以说我有一个名为Libitem一个父类,并呼吁Book子类。如果我在Libitem的指针地图内存储了一个Book的指针,当我尝试再次访问它时,是否会返回指针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? 
+0

请搜索并阅读关于* downcasting *。 –

回答

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块。

+0

好吧,整个转换机制将会非常有帮助......但只是为了确保存储在'catalog [1]'中的指针始终是一个技术上的孩子对吗?换句话说,如果我将存储在'catalog [1]'中的指针传递给另一个向量或映射,我是否能够从新集合中检索它并仍然可以动态地将其转换为'Book'? –

+0

是的。实际实例的类型不会改变。您可以创建,复制和转换指针。如果最终指针指向您分配对象的同一位置,则可以向下转发它。 –

2

这就像任何其他晶指针:一个Libitem的功能,但在方法Book的任何虚拟覆盖。

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

当然,如果你是一个强硬样的人,你可以向下转换(由@SomeProgrammerDude指出)。

+0

等等,这样只能访问一本书的虚拟覆盖?所有不是虚拟的,而是“Book”(而不是从'Libitem'继承)的一部分将不可访问? –

+0

任何不是从'Libitem'继承的东西都是不可访问的 –