Team LiB
Previous Section Next Section

18.2. Run-Time Type Identification

18.2. 运行时类型识别

Run-time Type Identification (RTTI) allows programs that use pointers or references to base classes to retrieve the actual derived types of the objects to which these pointers or references refer.

通过运行时类型识别(RTTI),程序能够使用基类的指针或引用来检索这些指针或引用所指对象的实际派生类型。

RTTI is provided through two operators:

通过下面两个操作符提供 RTTI:

  1. The typeid operator, which returns the actual type of the object referred to by a pointer or a reference

    typeid 操作符,返回指针或引用所指对象的实际类型。

  2. The dynamic_cast operator, which safely converts from a pointer or reference to a base type to a pointer or reference to a derived type

    dynamic_cast 操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。

These operators return dynamic type information only for classes with one or more virtual functions. For all other types, information for the static (i.e., compile-time) type is returned.

这些操作符只为带有一个或多个虚函数的类返回动态类型信息,对于其他类型,返回静态(即编译时)类型的信息。



The RTTI operators execute at run time for classes with virtual functions, but are evaluated at compile time for all other types.

对于带虚函数的类,在运行时执行 RTTI 操作符,但对于其他类型,在编译时计算 RTTI 操作符。

Dynamic casts are needed when we have a reference or pointer to a base class but need to perform operations from the derived class that are not part of the base class. Ordinarily, the best way to get derived behavior from a pointer to base is to do so through a virtual function. When we use virtual functions, the compiler automatically selects the right function according to the actual type of the object.

当具有基类的引用或指针,但需要执行不是基类组成部分的派生类操作的时候,需要动态的强制类型转换。通常,从基类指针获得派生类行为最好的方法是通过虚函数。当使用虚函数的时候,编译器自动根据对象的实际类型选择正确的函数。

In some situations however, the use of virtual functions is not possible. In these cases, RTTI offers an alternate mechanism. However, this mechanism is more error-prone than using virtual member functions: The programmer must know to which type the object should be cast and must check that the cast was performed successfully.

但是,在某些情况下,不可能使用虚函数。在这些情况下,RTTI 提供了可选的机制。然而,这种机制比使用虚函数更容易出错:程序员必须知道应该将对象强制转换为哪种类型,并且必须检查转换是否成功执行了。

Dynamic casts should be used with caution. Whenever possible, it is much better to define and use a virtual function rather than to take over managing the types directly.

使用动态强制类型转换要小心。只要有可能,定义和使用虚函数比直接接管类型管理好得多。



18.2.1. The dynamic_cast Operator

18.2.1. dynamic_cast 操作符

The dynamic_cast operator can be used to convert a reference or pointer to an object of base type to a reference or pointer to another type in the same hierarchy. The pointer used with a dynamic_cast must be validit must either be 0 or point to an object.

可以使用 dynamic_cast 操作符将基类类型对象的引用或指针转换为同一继承层次中其他类型的引用或指针。与 dynamic_cast 一起使用的指针必须是有效的——它必须为 0 或者指向一个对象。

Unlike other casts, a dynamic_cast involves a run-time type check. If the object bound to the reference or pointer is not an object of the target type, then the dynamic_cast fails. If a dynamic_cast to a pointer type fails, the result of the dynamic_cast is the value 0. If a dynamic_cast to a reference type fails, then an exception of type bad_cast is thrown.

与其他强制类型转换不同,dynamic_cast 涉及运行时类型检查。如果绑定到引用或指针的对象不是目标类型的对象,则 dynamic_cast 失败。如果转换到指针类型的 dynamic_cast 失败,则 dynamic_cast 的结果是 0 值;如果转换到引用类型的 dynamic_cast 失败,则抛出一个 bad_cast 类型的异常。

The dynamic_cast operator therefore performs two operations at once. It begins by verifying that the requested cast is valid. Only if the cast is valid does the operator actually do the cast. In general, the type of the object to which the reference or pointer is bound isn't known at compile-time. A pointer to base can be assigned to point to a derived object. Similarly, a reference to base can be initialized by a derived object. As a result, the verification that the dynamic_cast operator performs must be done at run time.

因此,dynamic_cast 操作符一次执行两个操作。它首先验证被请求的转换是否有效,只有转换有效,操作符才实际进行转换。一般而言,引用或指针所绑定的对象的类型在编译时是未知的,基类的指针可以赋值为指向派生类对象,同样,基类的引用也可以用派生类对象初始化,因此,dynamic_cast 操作符执行的验证必须在运行时进行。

Using the dynamic_cast Operator
使用 dynamic_cast 操作符

As a simple example, assume that Base is a class with at least one virtual function and that class Derived is derived from Base. If we have a pointer to Base named basePtr, we can cast it at run time to a pointer to Derived as follows:

作为例子,假定 Base 是至少带一个虚函数的类,并且 Derived 类派生于 Base 类。如果有一个名为 basePtr 的指向 Base 的指针,就可以像这样在运行时将它强制转换为指向 Derived 的指针:

     if (Derived *derivedPtr = dynamic_cast<Derived*>(basePtr))
     {
         // use the Derived object to which derivedPtr points
     } else { // BasePtr points at a Base object
         // use the Base object to which basePtr points
     }

At run time, if basePtr actually points to a Derived object, then the cast will be successful, and derivedPtr will be initialized to point to the Derived object to which basePtr points. Otherwise, the result of the cast is 0, meaning that derivedPtr is set to 0, and the condition in the if fails.

在运行时,如果 basePtr 实际指向 Derived 对象,则转换将成功,并且 derivedPtr 将被初始化为指向 basePtr 所指的 Derived 对象;否则,转换的结果是 0,意味着将 derivedPtr 置为 0,并且 if 中的条件失败。

We can apply a dynamic_cast to a pointer whose value is 0. The result of doing so is 0.

可以对值为 0 的指针应用 dynamic_cast,这样做的结果是 0。



By checking the value of derivedPtr, the code inside the if knows that it is operating on a Derived object. It is safe for that code to use Derived operations. If the dynamic_cast fails because basePtr refers to a Base object, then the else clause does processing appropriate to Base instead. The other advantage of doing the check inside the if condition is that it is not possible to insert code between the dynamic_cast and testing the result of the cast. It is, therefore, not possible to use the derivedPtr inadvertently before testing that the cast was successful. A third advantage is that the pointer is not accessible outside the if. If the cast fails, then the unbound pointer is not available for use in later cases where the test might be forgotten.

通过检查 derivedPtr 的值,if 内部的代码知道它是在操作 Derived 对象,该代码使用 Derived 的操作是安全的。如果 dynamic_castbasePtr 引用了 Base 对象而失败,则 else 子句进行适应于 Base 的处理来代替。在 if 条件内部进行检查的另一好处是,不可能在 dynamic_cast 和测试转换结果之间插入代码,因此,不可能在测试转换是否成功之前不经意地使用 derivedPtr。第三个好处是,在 if 外部不能访问该指针,如果转换失败,则在后面的忘了测试的地方,未绑定的指针是不可用的。

Performing a dynamic_cast in a condition ensures that the cast and test of its result are done in a single expression.

在条件中执行 dynamic_cast 保证了转换和其结果测试在一个表达式中进行。



Using a dynamic_cast and Reference Types
使用 dynamic_cast 和引用类型

In the previous example, we used a dynamic_cast to convert a pointer to base to a pointer to derived. A dynamic_cast can also be used to convert a reference to base to a reference to derived. The form for this a dynamic_cast operation is the following,

在前面例子中,使用了 dynamic_cast 将基类指针转换为派生类指针,也可以使用 dynamic_cast 将基类引用转换为派生类引用,这种 dynamic_cast 操作的形式如下:

     dynamic_cast< Type& >(val)

where Type is the target type of the conversion, and val is an object of base class type.

这里,Type 是转换的目标类型,而 val 是基类类型的对象。

The dynamic_cast operation converts the operand val to the desired type Type& only if val actually refers to an object of the type Type or is an object of a type derived from Type.

只有当 val 实际引用一个 Type 类型对象,或者 val 是一个 Type 派生类型的对象的时候,dynamic_cast 操作才将操作数 val 转换为想要的 Type& 类型。

Because there is no such thing as a null reference, it is not possible to use the same checking strategy for references that is used for pointer casts. Instead, when a cast fails, it throws a std::bad_cast exception. This exception is defined in the typeinfo library header.

因为不存在空引用,所以不可能对引用使用用于指针强制类型转换的检查策略,相反,当转换失败的时候,它抛出一个 std::bad_cast 异常,该异常在库头文件 typeinfo 中定义。

We might rewrite the previous example to use references as follows:

可以重写前面的例子如下,以便使用引用:

     void f(const Base &b)
     {
        try {
            const Derived &d = dynamic_cast<const Derived&>(b);
        // use the Derived object to which b referred
        } catch (bad_cast) {
            // handle the fact that the cast failed
        }
     }

Exercises Section 18.2.1

Exercise 18.13:

Given the following class hierarchy in which each class defines a public default constructor and virtual destructor,

给定下面的类层次,其中每个类都定义了 public 默认构造函数和虚析构函数。

     class A { /* ... */ };
     class B : public A { /* ... */ };
     class C : public B { /* ... */ };
     class D : public B, public A { /* ... */ };

which, if any, of the following dynamic_casts fail?

如果有,下面哪些 dynamic_casts 失败?

     (a) A *pa = new C;
         B *pb = dynamic_cast< B* >(pa);

     (b) B *pb = new B;
         C *pc = dynamic_cast< C* >(pb);

     (c) A *pa = new D;
         B *pb = dynamic_cast< B* >(pa);

Exercise 18.14:

What would happen in the last conversion in the previous exercise if both D and B inherited from A as a virtual base class?

如果 DB 都以 A 为虚基类,上题最后一个转换中将发生什么?

Exercise 18.15:

Using the class hierarchy defined in the previous exercise, rewrite the following piece of code to perform a reference dynamic_cast to convert the expression *pa to the type C&:

使用上面习题中定义的类层次,重写下面代码片段,以便执行 dynamic_cast 将表达式 *pa 转换为 C& 类型:

     if (C *pc = dynamic_cast< C* >(pa))
         // use C's members
     } else {
         // use A's members
     }

Exercise 18.16:

Explain when you would use dynamic_cast instead of a virtual function.

解释什么时候可以使用 dynamic_cast 代替虚函数。


18.2.2. The typeid Operator

18.2.2. typeid 操作符

The second operator provided for RTTI is the typeid operator. The typeid operator allows a program to ask of an expression: What type are you?

为 RTTI 提供的第二个操作符是 typeid 操作符typeid 操作符使程序能够问一个表达式:你是什么类型?

A typeid expression has the form

typeid 表达式形如:

     typeid(e)

where e is any expression or a type name.

这里 e 是任意表达式或者是类型名。

If the type of the expression is a class type and that class contains one or more virtual functions, then the dynamic type of the expression may differ from its static compile-time type. For example, if the expression dereferences a pointer to a base class, then the static compile-time type of that expression is the base type. However, if the pointer actually addresses a derived object, then the typeid operator will say that the type of the expression is the derived type.

如果表达式的类型是类类型且该类包含一个或多个虚函数,则表达式的动态类型可能不同于它的静态编译时类型。例如,如果表达式对基类指针解引用,则该表达式的静态编译时类型是基类类型;但是,如果指针实际指向派生类对象,则 typeid 操作符将说表达式的类型是派生类型。

The typeid operator can be used with expressions of any type. Expressions of built-in type as well as constants can be used as operands for the typeid operator. When the operand is not of class type or is a class without virtual functions, then the typeid operator indicates the static type of the operand. When the operand has a class-type that defines at least one virtual function, then the type is evaluated at run time.

typeid 操作符可以与任何类型的表达式一起使用。内置类型的表达式以及常量都可以用作 typeid 操作符的操作数。如果操作数不是类类型或者是没有虚函数的类,则 typeid 操作符指出操作数的静态类型;如果操作数是定义了至少一个虚函数的类类型,则在运行时计算类型。

The result of a typeid operation is a reference to an object of a library type named type_info. Section 18.2.4 (p. 779) covers this type in more detail. To use the type_info class, the library header typeinfo must be included.

typeid 操作符的结果是名为 type_info 的标准库类型的对象引用,第 18.2.4 节将更详细地讨论这个类型。要使用 type_info 类,必须包含库头文件 typeinfo

Using the typeid Operator
使用 typeid 操作符

The most common use of typeid is to compare the types of two expressions or to compare the type of an expression to a specified type:

typeid 最常见的用途是比较两个表达式的类型,或者将表达式的类型与特定类型相比较:

     Base *bp;
     Derived *dp;
     // compare type at run time of two objects
     if (typeid(*bp) == typeid(*dp)) {
         // bp and dp point to objects of the same type
     }
     // test whether run time type is a specific type
     if (typeid(*bp) == typeid(Derived)) {
         // bp actually points to a Derived
     }

In the first if, we compare the actual types of the objects to which bp and dp point. If they both point to the same type, then the test succeeds. Similarly, the second if succeeds if bp currently points to a Derived object.

第一个 if 中,比较 bp 所指对象与 dp 所指对象的实际类型,如果它们指向同一类型,则测试成功。类似地,如果 bp 当前指向 Derived 对象,则第二个 if 成功。

Note that the operands to the typeid are expressions that are objectswe tested *bp, not bp:

注意,typeid 的操作数是表示对象的表达式——测试 *bp,而不是 bp

     // test always fails: The type of bp is pointer to Base
     if (typeid(bp) == typeid(Derived)) {
          // code never executed
     }

This test compares the type Base* to type Derived. These types are unequal, so this test will always fail regardless of the type of the object to which bp points.

这个测试将 Base* 类型与 Derived 类型相比较,这两个类型不相等,所以,无论 bp 所指对象的类型是什么,这个测试将问题失败。

Dynamic type information is returned only if the operand to typeid is an object of a class type with virtual functions. Testing a pointer (as opposed to the object to which the pointer points) returns the static, compile-time type of the pointer.

只有当 typeid 的操作数是带虚函数的类类型的对象的时候,才返回动态类型信息。测试指针(相对于指针指向的对象)返回指针的静态的、编译时类型。



If the value of a pointer p is 0, then typeid(*p) throws a bad_typeid exception if the type of p is a type with virtual functions. If the type of p does not define any virtuals, then the value of p is irrelevant. As when evaluating a sizeof expression (Section 5.8, p. 167) the compiler does not evaluate *p. It uses the static type of p, which does not require that p itself be a valid pointer.

如果指针 p 的值是 0,那么,如果 p 的类型是带虚函数的类型,则 typeid(*p) 抛出一个 bad_typeid 异常;如果 p 的类型没有定义任何虚函数,则结果与 p 的值是不相关的。正像计算表达式 sizeof第 5.8 节)一样,编译器不计算 *p,它使用 p 的静态类型,这并不要求 p 本身是有效指针。

Exercises Section 18.2.2

Exercise 18.17:

Write an expression to dynamically cast a pointer to a Query_base to a pointer to an AndQuery. Test the cast by using objects of AndQuery and of another query type. Print a statement indicating whether the cast works and be sure that the output matches your expectations.

编写一个表达式,动态地将 Query_base 对象的指针强制转换为 AndQuery 对象的指针。通过使用 AndQuery 和其他查询类型的对象测试该转换。显示一个语句指出强制转换是否工作,并确信输出与你的表达式匹配。

Exercise 18.18:

Write the same cast, but cast a Query_base object to a reference to AndQuery. Repeat the test to ensure that your cast works correctly.

编写相同的强制转换,但将 Query_base 对象转换为 AndQuery 的引用。重复测试以确信你的转换正确工作。

Exercise 18.19:

Write a typeid expression to see whether two Query_base pointers point to the same type. Now check whether that type is an AndQuery.

编写一个 typeid 表达式,看两个 Query_base 指针是否指向相同的类型,然后检查该类型是否为 AndQuery


18.2.3. Using RTTI

18.2.3. RTTI 的使用

As an example of when RTTI might be useful, consider a class hierarchy for which we'd like to implement the equality operator. Two objects are equal if they have the same value for a given set of their data members. Each derived type may add its own data, which we will want to include when testing for equality.

作为说明何时可以使用 RTTI 的例子,考虑一个类层次,我们希望为它实现相等操作符。如果两个对象的给定数据成员集合的值相同,它们就相等。每个派生类型可以增加自己的数据,我们希望在测试相等的时候包含这些数据。

Because the values considered in determining equality for a derived type might differ from those considered for the base type, we'll (potentially) need a different equality operator for each pair of types in the hierarchy. Moreover, we'd like to be able to use a given type as either the left-hand or right-hand operand, so we'll actually need two operators for each pair of types.

因为确定派生类型的相等与确定基类类型的相等所考虑的值不同,所以对层次中的每一对类型(潜在地)需要一个不同的相等操作符。而且,希望能够使用给类型作为左操作数或右操作数,所以实际上对每一对类型将需要两个操作符。

If our hierarchy has only two types, we need four functions:

如果类层次中只有两个类型,就需要四个函数:

     bool operator==(const Base&, const Base&)
     bool operator==(const Derived&, const Derived&)
     bool operator==(const Derived&, const Base&);
     bool operator==(const Base&, const Derived&);

But if our hierarchy has several types, the number of operators we must define expands rapidlyfor only 3 types we'd need 9 operators. If the hierarchy has 4 types, we'd need 16, and so on.

但是,如果类层次中有几个类型,必须定义的操作符的数目就迅速扩大——仅仅 3 个类型就需要 9 个操作符。如果类层次有 4 个类型,将需要 16 个操作符,以此类推。

We might think we could solve this problem by defining a set of virtual functions that would perform the equality test at each level in the hierarchy. Given those virtuals, we could define a single equality operator that operates on references to the base type. That operator could delegate its work to a virtual equal operation that would do the real work.

也许我们认为可以通过定义一个虚函数集合来解决这个问题,这些虚函数可以在类层次中每一层执行相等测试。给定这些虚函数,可以定义单个相等操作符,操作基类类型的引用,该操作符可以将工作委派给可以完成实际工作的虚操作。

Unfortunately, virtual functions are not a good match to this problem. The trouble is deciding on the type for the parameter to the equal operation. Virtual functions must have the same parameter type(s) in both the base and derived classes. That implies that a virtual equal operation must have a parameter that is a reference to the base class.

但是,虚函数并不是解决这个问题的好办法。麻烦在于决定 equal 操作的形参的类型。虚函数在基类类型和派生类型中必须有相同的形参类型,这意味着,虚 equal 操作必须有一个形参是基类的引用。

However, when we compare two derived objects, we want to compare data members that might be particular to that derived class. If the parameter is a reference to base, we can use only members that are present in the base class. We cannot access members that are in the derived class but not in the base.

但是,当比较两个派生类对象的时候,我们希望比较可能特定于派生类的数据成员。如果形参是基类的引用,就只能比较基类中出现的成员,我们不能访问在派生类中但不在基类中出现的成员。

Thinking about the problem in this detail, we see that we want to return false if we attempt to compare objects of different types. Given this observation, we can now use RTTI to solve our problem.

仔细考虑这个问题,我们看到,希望在试图比较不同类型的对象时返回假(false)。有了这个观察,现在可以使用 RTTI 解决我们的问题。

We'll define a single equality operator. Each class will define a virtual equal function that first casts its operand to the right type. If the cast succeeds, then the real comparison will be performed. If the cast fails, then the equal operation will return false.

我们将定义单个相等操作符。每个类定义一个虚函数 equal,该函数首先将操作数强制转换为正确的类型。如果转换成功,就进行真正的比较;如果转换失败,equal 操作就返回 false

The Class Hierarchy
类层次

To make the concept a bit more concrete, let's assume that our classes look something like:

为了使概念更清楚一点,假定类层次是这样的:

     class Base {
         friend bool operator==(const Base&, const Base&);
     public:
         // interface members for Base
     protected:
         virtual bool equal(const Base&) const;
         // data and other implementation members of Base
     };
     class Derived: public Base {
         friend bool operator==(const Base&, const Base&);
     public:
         // other interface members for Derived
     private:
         bool equal(const Base&) const;
         // data and other implementation members of Derived
     };

A Type-Sensitive Equality Operator
类型敏感的相等操作符

Next let's look at how we might define the overall equality operator:

下面看看可以怎样定义整体的相等操作符:

     bool operator==(const Base &lhs, const Base &rhs)
     {
        // returns false if typeids are different otherwise
        // returns lhs.equal(rhs)
        return typeid(lhs) == typeid(rhs) && lhs.equal(rhs);
     }

This operator returns false if the operands are different types. If they are the same type, then it delegates the real work of comparing the operands to the appropriate virtual equal function. If the operands are Base objects, then Base::equal will be called. If they are Derived objects, Derived::equal is called.

如果操作数类型不同,这个操作符就返回假;如果操作数类型相同,它就将实际比较操作数的工作委派给适当的虚函数 equal。如果操作数是 Base 对象,就调用 Base::equal;如果操作数是 Derived 对象,就调用 Derived::equal

The Virtual equal Functions
虚函数 equal

Each class in the hierarchy must define its own version of equal. The functions in the derived classes will all start the same way: They'll cast their argument to the type of the class itself:

层次中的每个类都必须定义自己的 equal 版本。派生类中的 equal 函数将以相同的方式开始:它们将实参强制转换为类本身的类型。

     bool Derived::equal(const Base &rhs) const
     {
        if (const Derived *dp
                   = dynamic_cast<const Derived*>(&rhs)) {
           // do work to compare two Derived objects and return result
        } else
           return false;
     }

The cast should always succeedafter all, the function is called from the equality operator only after testing that the two operands are the same type. However, the cast is necessary so that the function can access the derived members of the right-hand operand. The operand is a Base&, so if we want to access members of the Derived, we must first do the cast.

这个强制转换应该总是成功——毕竟,只有有测试了两个操作数类型相同之后,才从相等操作符调用该函数。但是,这个强制转换是必要的,以便函数可以访问右操作数的派生类成员。因为操作数是 Base&,所以如果想要访问 Derived 的成员,就必须首先进行强制转换。

The Base-Class equal Function
基类 equal 函数

This operation is a bit simpler than the others:

这个操作比其他的简单一点:

     bool Base::equal(const Base &rhs) const
     {
          // do whatever is required to compare to Base objects
     }

There is no need to cast the parameter before using it. Both *this and the parameter are Base objects, so all the operations available for this object are also defined for the parameter type.

使用形参之前不必强制转换,*this 和形参都是 Base 对象,所以对形参类型也定义了该对象可用的所有操作。

18.2.4. The type_info Class

18.2.4. type_info

The exact definition of the type_info class varies by compiler, but the standard guarantees that all implementations will provide at least the operations listed in Table 18.2

type_info 类的确切定义随编译器而变化,但是,标准保证所有的实现将至少提供表 18.2 列出的操作。

Table 18.2. Operations on type_info
表 18.2. type_info 的操作

t1 == t2

Returns true if the two type_info objects t1 and t2 refer to the same type; false otherwise.

如果两个对象 t1t2 类型相同,就返回 true;否则,返回 false

t1 != t2

Returns true if the two type_info objects t1 and t2 refer to different types; false otherwise.

如果两个对象 t1t2 类型不同,就返回 true;否则,返回 false

t.name()

Returns a C-style character string that is a printable version of the type name. Type names are generated in a system-dependent way.

返回 C 风格字符串,这是类型名字的可显示版本。类型名字用系统相关的方法产生

t1.before(t2)

Returns a bool that indicates whether t1 comes before t2. The ordering imposed by before is compiler-dependent.

返回指出 t1 是否出现在 t2 之前的 bool 值。before 强制的次序与编译器有关


The class also provides a public virtual destructor, because it is intended to serve as a base class. If the compiler wants to provide additional type information, it should do so in a class derived from type_info.

因为打算作基类使用,type_info 类也提供公用虚析构函数。如果编译器想要提供附加的类型信息,应该在 type_info 的派生类中进行。

The default and copy constructors and the assignment operator are all defined as private, so we cannot define or copy objects of type type_info. The only way to create type_info objects in a program is to use the typeid operator.

默认构造函数和复制构造函数以及赋值操作符都定义为 private,所以不能定义或复制 type_info 类型的对象。程序中创建 type_info 对象的唯一方法是使用 typeid 操作符。

The name function returns a C-style character string for the name of the type represented by the type_info object. The value used for a given type depends on the compiler and in particular is not required to match the type names as used in a program. The only guarantee we have about the return from name is that it returns a unique string for each type. Nonetheless, the name member can be used to print the name of a type_info object:

name 函数为 type_info 对象所表示的类型的名字返回 C 风格字符串。给定类型所用的值取决于编译器,具体来说,无须与程序中使用的类型名字匹配。对 name 返回值的唯一保证是,它为每个类型返回唯一的字符串。虽然如此,仍可以使用 name 成员来显示 type_info 对象的名字:

     int iobj;
     cout << typeid(iobj).name() << endl
          << typeid(8.16).name() << endl
          << typeid(std::string).name() << endl
          << typeid(Base).name() << endl
          << typeid(Derived).name() << endl;

The format and value returned by name varies by compiler. This program, when executed on our machine, generates the following output:

name 返回的格式和值随编译器而变化。在我们的机器上执行时,这个程序产生下面的输出:

     i
     d
     Ss
     4Base
     7Derived

The type_info class varies by compiler. Some compilers provide additional member functions that provide additional information about types used in a program. You should consult the reference manual for your compiler to understand the exact type_info support provided.

type_info 类随编译器而变。一些编译器提供附加的成员函数,那些函数提供关于程序中所用类型的附加信息。你应该查阅编译器的参考手册来理解所提供的确切的 type_info 支持。



Exercises Section 18.2.4

Exercise 18.20:

Given the following class hierarchy in which each class defines a public default constructor and virtual destructor, which type name do the following statements print?

给定下面的类层次,其中每个类都定义了 public 默认构造函数及虚析构函数,下面语句显示哪些类型名?

     class A { /* ... */ };
     class B : public  A { /* ... */ };
     class C : public  B { /* ... */ };

     (a) A *pa = new C;
         cout << typeid(pa).name() << endl;

     (b) C cobj;
         A& ra = cobj;
         cout << typeid(&ra).name() << endl;

     (c) B *px = new B;
         A& ra = *px;
         cout << typeid(ra).name() << endl;


Team LiB
Previous Section Next Section