⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch07.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD>	<META NAME="Author" Content="Steph Mineart">	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">	<TITLE>ANSI/ISO C++ Professional Programmer's Handbook - Chapter 7 - Runtime Type Identification</TITLE>	<link rel="stylesheet"  TYPE="text/css" href="/includes/stylesheets/ebooks.css"></head><BODY TEXT="#000000" BGCOLOR="#FFFFFF"><CENTER><H1><img src="/publishers/que/series/professional/0789720221/button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>ANSI/ISO C++ Professional Programmer's Handbook</H1></CENTER><CENTER>  <P><A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A>   <HR></CENTER><H1 align="center">7</H1><h1 align="center"> Runtime Type Identification</h1><address>by Danny Kalev </address><ul>  <li><a href="#Heading1">Introduction</a>   <li><a href="#Heading2">Structure Of This Chapter</a>   <li><a href="#Heading3"> Making Do Without RTTI</a>     <ul>      <li><a href="#Heading4">Virtual member functions can provide a reasonable         level of dynamic typing without the need for additional RTTI support.         A well-designed class hierarchy can define a meaningful operation for         every virtual member function that is declared in the base class.</a>     </ul>  <li><a href="#Heading5">RTTI constituents</a>     <ul>      <li><a href="#Heading6">RTTI Is Applicable to Polymorphic Objects Exclusively</a>       <li><a href="#Heading7">Class type_info</a>       <li><a href="#Heading8">Operator typeid</a>       <li><a href="#Heading9">Operator dynamic_cast&lt;&gt;</a>       <li><a href="#Heading10">Other Uses of dynamic_cast&lt;&gt;</a>     </ul>  <li><a href="#Heading11">The Cost of Runtime Type Information</a>     <ul>      <li><a href="#Heading12">Memory Overhead</a>       <li><a href="#Heading13">Runtime Type Information of Polymorphic Objects</a>       <li><a href="#Heading14">Additional Overhead</a>       <li><a href="#Heading15">RTTI Support Can Usually Be Toggled</a>       <li><a href="#Heading16">typeid Versus dynamic_cast&lt;&gt;</a>     </ul>  <li><a href="#Heading17">Conclusions</a> </ul><hr size=4><h2><a name="Heading1">Introduction</a></h2><p>Originally, C++ did not provide standardized support for runtime type information   (RTTI). Furthermore, its creators balked at the idea of adding RTTI support   for at least two reasons. First, they wanted to preserve backward compatibility   with C. Secondly, they were concerned about efficiency. Other RTTI-enabled languages,   such as Smalltalk and Lisp, were characterized by their notoriously sluggish   performance. The performance penalty of dynamic type checking results from the   relatively slow process of retrieving the object's type at runtime as well as   from the additional information that the system needs to store for every type.   C++ designers wanted to preserve the efficiency of C. </p><p>Another claim against the addition of RTTI to the language was that, in many   cases, the use of virtual member functions could serve as an alternative to   explicit runtime type checking. However, the addition of multiple inheritance   (and consequently, of virtual inheritance) to C++ gave overwhelming ammunition   to the proponents of RTTI (multiple inheritance is discussed in Chapter 5, "Object-Oriented   Programming and Design"); it became apparent that under some circumstances,   static type checking and virtual functions were insufficient.</p><p>Eventually, the C++ standardization committee approved the addition of RTTI   to the language. Two new operators, <tt>dynamic_cast&lt;&gt;</tt> and <tt>typeid</tt>,   were introduced. In addition, the class <tt>std::type_info</tt> was added to   the Standard Library.</p><h2> <a name="Heading2">Structure Of This Chapter</a></h2><p>This chapter consists of three major parts. The limitations of virtual functions   are presented first. Then, the standard RTTI constituents are explained and   exemplified. Finally, RTTI performance and design issues are discussed. </p><p></p><h2> <a name="Heading3"> Making Do Without RTTI</a></h2><p> <a name="Heading4">Virtual member functions can provide a reasonable level   of dynamic typing without the need for additional RTTI support. A well-designed   class hierarchy can define a meaningful operation for every virtual member function   that is declared in the base class.</a></p><p>Suppose you have to develop a file manager application as a component of a   GUI-based operating system. The files in this system are represented as icons   that respond to the right click of a mouse, displaying a menu with options such   as open, close, read, and so on. The underlying implementation of the file system   relies on a class hierarchy that represents files of various types. In a well-designed   class hierarchy, there is usually an abstract class serving as an interface:</p><pre><tt>class File //abstract,  all members are pure virtual</tt><tt>{</tt><tt>  public: virtual void open() =0;  </tt><tt>  public: virtual void read() =0;</tt><tt>  public: virtual void write() =0;</tt><tt>  public: virtual ~File () =0;</tt><tt>};</tt><tt>File::~File ()  //pure virtual destructor must be defined</tt><tt>{}</tt></pre><p>At a lower level in the hierarchy, you have a set of derived classes that implement   the common interface that they inherit from <tt>File</tt>. Each of these subclasses   represents a different family of files. To simplify the discussion, assume that   there are only two file types in this system: binary .exe files and text files.</p><pre><tt>class BinaryFile : public File</tt><tt>{</tt><tt>public:</tt><tt>  void open () { OS_execute(this); }  //implement the pure virtual function</tt><tt>  //...other member functions</tt><tt>};</tt><tt>class TextFile : public File</tt><tt>{</tt><tt>public:</tt><tt>  void open () { Activate_word_processor (this); }  </tt><tt>  //...other member functions of File are implemented here</tt><tt>  void virtual print();  // an additional member function</tt><tt>};</tt></pre><p>The pure virtual function <tt>open()</tt> is implemented in every derived class,   according to the type of the file. Thus, in a <tt>TextFile</tt> object, <tt>open()</tt>   activates a word processor, whereas a <tt>BinaryFile</tt> object invokes the   operating system's API function <tt>OS_execute()</tt>, which in turn executes   the program that is stored in the binary file.</p><p>There are several differences between a binary file and a text file. For example,   a text file can be printed directly on a screen or a printer because it consists   of a sequence of printable characters. Conversely, a binary file with an .exe   extension contains a stream of bits; it cannot be printed or displayed directly   on a screen. It must be converted to a text file first, usually by a utility   that translates the binary data into their symbolic representations. (For instance,   the sequence <tt>0110010</tt> in an executable file can be replaced by a corresponding   <cite>move esp, ebp</cite><i> </i>assembly directive.) In other words, an executable   file must be converted to a text file in order to be viewed or printed. Therefore,   the member function <tt>print()</tt> appears only in class <tt>TextFile</tt>.</p><p>In this file manager, right-clicking the mouse on a file icon opens a menu   of messages (options) to which the object can respond. For that purpose, the   operating system has a function that takes a reference to a <tt>File</tt>:</p><pre><tt>OnRightClick (File &amp; file); //operating system's API function</tt></pre><p>Obviously, no object of class <tt>File</tt> can be instantiated because <tt>File</tt>   is an abstract class (see Chapter 5). However, the function <tt>OnRightClick()</tt>   can accept any object that is derived from <tt>File</tt>. When the user right-clicks   on a file icon and chooses the option Open, for instance, <tt>OnRightClick</tt>   invokes the virtual member function <tt>open</tt> of its argument, and the appropriate   member function is called. For example</p><pre><tt>OnRightClick (File &amp; file)</tt><tt>{</tt><tt>  switch (message)</tt><tt>  {</tt><tt>  //...</tt><tt>  case m_open:</tt><tt>    file.open();</tt><tt>  break;</tt><tt>  }</tt><tt>}</tt></pre><p>So far, so good. You have implemented a polymorphic class hierarchy and a function   that does not depend on the dynamic type of its argument. In this case, the   language support for virtual functions was sufficient for your purposes; you   did not need any explicit runtime type information (RTTI). Well, not exactly.   You might have noticed the lack of file printing support. Look at the definition   of class <tt>TextFile</tt> again:</p><pre><tt>class TextFile : public File</tt><tt>{</tt><tt>public:</tt><tt>  void open () { Activate_word_processor (this); } </tt><tt>  void virtual print();</tt><tt>};</tt></pre><p>The member function <tt>print()</tt> is not a part of the common interface   that is implemented by all files in your system. It would be a design error   to move <tt>print()</tt> to the abstract class <tt>File</tt> because binary   files are nonprintable and cannot define a meaningful operation for it. Then   again, <tt>OnRightClick()</tt> has to support file printing when it handles   a text file. In this case, ordinary polymorphism in the form of virtual member   functions will not do. <tt>OnRightClick()</tt> only knows that its argument   is derived from <tt>File</tt>. However, this information is not sufficient to   tell whether the actual object is printable. Clearly, <tt>OnRightClick()</tt>   needs more information about the dynamic type of its argument in order to properly   handle file printing. This is where the need for runtime type information arises.   Before delving into the implementation of <tt>OnRightClick()</tt>, an overview   of RTTI constituents and their role is necessary.</p><h2> <a name="Heading5">RTTI constituents</a></h2><p>The operators <tt>typeid</tt> and <tt>dynamic_cast&lt;&gt;</tt> offer two complementary   forms of accessing the runtime type information of their operand. The operand's   runtime type information itself is stored in a <tt>type_info</tt> object. This   section exemplifies how these three constituents are used.</p><h3> <a name="Heading6">RTTI Is Applicable to Polymorphic Objects Exclusively</a></h3><p>It is important to realize that RTTI is applicable solely to polymorphic objects.   A class must have at least one virtual member function in order to have RTTI   support for its objects. C++ does not offer RTTI support for non-polymorphic   classes and primitive types. This restriction is just common sense -- a fundamental   type such as <tt>double</tt> or a concrete class such as <tt>string</tt> cannot   change its type at runtime. Therefore, there is no need to detect their dynamic   types because they are identical to their static types. But there is also a   practical reason for confining RTTI support to polymorphic classes exclusively,   as you will see momentarily.</p><p>As you probably know, every object that has at least one virtual member function   also contains a special data member that is added by the compiler (more on this   in Chapter 13, "C Language Compatibility Issues"). This member is a pointer   to the virtual function table. The runtime type information is stored in this   table, as is a pointer to a <tt>std::type_info</tt> object.</p><h3> <a name="Heading7">Class type_info</a></h3><p>For every distinct type, C++ instantiates a corresponding RTTI object that   contains the necessary runtime type information. The RTTI object is an instance   of the standard class <tt>std::type_info</tt> or an implementation-defined class   derived from it. (<tt>std::type_info</tt> is defined in the standard header   &lt;typeinfo&gt;). Th<tt>is</tt> object is owned by the implementation and cannot   be altered in any way by the programmer. The interface of <tt>type_info</tt>   looks similar to the following (namespaces will be covered in Chapter 8, "Namespaces"):</p><pre><tt>namespace std { //class type_info is declared in namespace std</tt><tt>  class type_info</tt><tt>  {</tt><tt>  public:</tt><tt>    virtual ~type_info(); //type_info can serve as a base class</tt><tt>    bool operator==(const type_info&amp;  rhs ) const; // enable comparison </tt><tt>    bool operator!=(const type_info&amp;  rhs ) const; // return !( *this == rhs)</tt><tt>    bool before(const type_info&amp;  rhs ) const; // ordering</tt><tt>    const char* name() const; //return a C-string containing the type's name</tt><tt>  private:</tt><tt>    //objects of this type cannot be copied</tt><tt>         type_info(const type_info&amp;  rhs );</tt><tt>         type_info&amp; operator=(const type_info&amp;  rhs);</tt><tt>  }; //type_info</tt>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -