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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 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>

⌨️ 快捷键说明

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