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

📄 ch09.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<!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 9 - Templates</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">9</H1><h1 align="center"> Templates</h1><address>by Danny Kalev</address><ul>  <li><a href="#Heading1">Introduction</a>   <li><a href="#Heading2">Class Templates</a>     <ul>      <li><a href="#Heading3">Declaration of a Class Template</a>       <li><a href="#Heading4">Instantiation and Specialization</a>       <li><a href="#Heading5">Template Arguments</a>       <li><a href="#Heading6">Default Type Arguments</a>       <li><a href="#Heading7">Static Data Members</a>       <li><a href="#Heading8">Friendship</a>       <li><a href="#Heading9">Partial Specialization</a>       <li><a href="#Heading10">Explicit Specialization of a Class Template</a>       <li><a href="#Heading11">Specializations of Class Template Functions</a>     </ul>  <li><a href="#Heading12">Function Templates</a>     <ul>      <li><a href="#Heading13">Function-Like Macros</a>       <li><a href="#Heading14">void Pointers</a>       <li><a href="#Heading15">A Common Root Base</a>     </ul>  <li><a href="#Heading16">Performance Considerations</a>     <ul>      <li><a href="#Heading17">Type Equivalence</a>       <li><a href="#Heading18">Avoiding Unnecessary Instantiations</a>       <li><a href="#Heading19">Explicit Template Instantiation</a>       <li><a href="#Heading20"> Exported Templates</a>     </ul>  <li><a href="#Heading21">Interaction with Other Language Features</a>     <ul>      <li><a href="#Heading22">The typename Keyword</a>       <li><a href="#Heading23">Inheritance Relationship of Templates</a>       <li><a href="#Heading24">Virtual Member Functions</a>       <li><a href="#Heading25">Pointers to Members of a Class Template</a>     </ul>  <li><a href="#Heading26">Conclusions</a> </ul><hr size=4><h2><a name="Heading1">Introduction</a></h2><p>A <i>template</i> is a mold from which the compiler generates a family of classes   or functions. C++ programming styles and concepts have changed considerably   since the first implementation of templates back in 1991 (in <tt>cfront</tt>   2.0). Initially, templates were viewed as a support for generic container classes   such as <tt>Array</tt> and <tt>List</tt>. In recent years, the experience of   using templates has shown that this feature is most useful in designing and   implementing general-purpose libraries such as the Standard Template Library.   Templatized libraries and frameworks are both efficient and portable. With the   widespread usage of templates, C++ has added more sophisticated constructs to   control their behavior and performance, including partial specializations, explicit   specializations, template members, exported templates, default type arguments,   and more.</p><p>This chapter discusses various aspects of designing and implementing templates.   First, class templates are explained. Function templates come next. Finally,   template issues of special concern -- such as pointers to members, virtual member   functions within a template class, inheritance relations, and explicit instantiations   -- are discussed.</p><h2> <a name="Heading2">Class Templates</a></h2><p>Many algorithms and data structures can be defined independently of the concrete   data type that they manipulate. Often, the reliance on a hardwired data type   is merely a programming artifact. The concept of a complex number, for instance,   is not exclusively limited to the fundamental type <tt>double</tt>. Rather,   it is applicable to every floating-point type. Designing a type-independent   class that abstracts the concept of a complex number has many advantages because   it enables users to choose the desired level of precision for a specific application   without having to reduplicate code manually. In addition, type-independent classes   are more portable among different platforms and locales.</p><h3> <a name="Heading3">Declaration of a Class Template</a></h3><p>A class template is declared using the keyword <tt>template</tt>, followed   by a <i>template parameter list</i> that is enclosed in angular brackets and   a declaration or a definition of the class. For example</p><pre><tt>template &lt;class T&gt; class Vector; //declaration</tt><tt>template &lt;class T&gt; class Vector  //definition</tt><tt>{</tt><tt>private:</tt><tt>  size_t sz;</tt><tt>  T * buff;</tt><tt>public:</tt><tt>  explicit Vector&lt;T&gt;(size_t s = 100);</tt><tt>  Vector&lt;T&gt; (const Vector &lt;T&gt; &amp; v); //copy constructor</tt><tt>  Vector&lt;T&gt;&amp; operator= (const Vector&lt;T&gt;&amp; v); //assignment operator</tt><tt>  ~Vector&lt;T&gt;(); //destrcutor</tt><tt>  //other member functions</tt><tt>  T&amp; operator [] (unsigned int index);</tt><tt>  const T&amp; operator [] (unsigned int index) const;</tt><tt>  size_t size() const;</tt><tt>}; </tt></pre><p>Member functions of a class template can be defined outside the class body.   In this case, they have to be explicitly declared as member functions of their   class template. For example</p><pre><tt>//definitions of Vector's member functions</tt><tt>//follow the class declaration</tt><tt>template &lt;class T&gt; Vector&lt;T&gt;::Vector&lt;T&gt; (size_t s) //constructor definition</tt><tt>: sz(s),</tt><tt>buff (new T[s])</tt><tt>{}</tt><tt>template &lt;class T&gt; Vector&lt;T&gt;::Vector&lt;T&gt; (const Vector &lt;T&gt; &amp; v) //copy ctor</tt><tt>{</tt><tt>  sz = 0;</tt><tt>  buff = 0; </tt><tt>  *this = v; //use overloaded assignment operator</tt><tt>}</tt><tt>template &lt;class T&gt; Vector&lt;T&gt;&amp; Vector&lt;T&gt;::operator=   // assignment operator</tt><tt>(const Vector &lt;T&gt; &amp; v)</tt><tt>{</tt><tt>  if (this == &amp;v)</tt><tt>    return *this;</tt><tt>  this-&gt;Vector&lt;T&gt;::~Vector&lt;T&gt;(); //call destructor </tt><tt>  buff = new T[v.size()]; //allocate sufficient storage</tt><tt>  for (size_t i =0; i &lt; v.size(); i++)</tt><tt>    buff[i] = v[i]; //memberwise copy</tt><tt>  sz = v.size();</tt><tt>  return *this;</tt><tt>}</tt><tt>template &lt;class T&gt; Vector&lt;T&gt;::~Vector&lt;T&gt; () //destructor</tt><tt>{</tt><tt>  delete [] buff;</tt><tt>}</tt><tt>template &lt;class T&gt; inline T&amp; Vector&lt;T&gt;::operator [] (unsigned int i)</tt><tt>{</tt><tt>  return buff[i];</tt><tt>}</tt><tt>template &lt;class T&gt; inline const T&amp; Vector&lt;T&gt;::operator [] //const version</tt><tt>(unsigned int i) const</tt><tt>{</tt><tt>  return buff[i];</tt><tt>}</tt><tt>template &lt;class T&gt; inline size_t Vector&lt;T&gt;::size () const</tt><tt>{</tt><tt>  return sz;</tt><tt>}</tt><tt>//Vector.hpp</tt></pre><p>The prefix <tt>template &lt;class T&gt;</tt> indicates that <tt>T</tt> is a   <i>template parameter</i>, which is a placeholder for a yet unspecified type.   The keyword <tt>class</tt> is of particular interest because the corresponding   argument for the parameter <tt>T</tt> is not necessarily a user-defined type;   it can also be a fundamental type, such as <tt>char</tt> or <tt>int</tt>. If   you prefer a more neutral term, you can use the <tt>typename</tt> keyword instead   (<tt>typename</tt> also has other uses, though, as you will see next):</p><pre><tt>template &lt;<b>typename</b> T&gt; class Vector //typename instead of class</tt><tt>                               //no semantic difference between the two forms</tt><tt>{</tt><tt>  //...</tt><tt>};</tt><tt>template &lt;<b>typename</b> T&gt; Vector&lt;T&gt;::Vector&lt;T&gt; (size_t s)</tt><tt>: sz(s), buff (new T[s]) {}</tt></pre><p>Within the scope of <tt>Vector</tt>, qualification with the parameter <tt>T</tt>   is redundant, so the member functions can be declared and defined without it.   The constructor, for example, can be declared as follows:</p><pre><tt>template &lt;class T&gt; class Vector</tt><tt>{</tt><tt>public:</tt><tt> Vector (size_t s = 100);  // equivalent to Vector &lt;T&gt;(size_t s = 100);</tt><tt>};</tt></pre><p>Similarly, the constructor's definition can omit the redundant parameter:</p><pre><tt>// equivalent to template &lt;class T&gt; Vector&lt;T&gt;::Vector&lt;T&gt;(size_t s)</tt><tt>template &lt;class T&gt; Vector&lt;T&gt;::Vector (size_t s) :</tt><tt>buff (new T[s]), sz(s)</tt><tt>{}</tt></pre><h3> <a name="Heading4">Instantiation and Specialization</a></h3><p>A class template is not a class. The process of instantiating a class from   a class template and a type argument is called <i>template instantiation</i>.   A <i>template id</i>, that is, a template<i> </i>name followed by a list of   arguments in angular brackets (for example, <tt>Vector&lt;int&gt;</tt>), is   called a <i>specialization</i>. A specialization of a class template can be   used exactly like any other class. Consider the following examples:</p><pre><tt>void func (Vector &lt;float&gt; &amp;); //function parameter</tt><tt>size_t n = sizeof( Vector &lt;char&gt;); //sizeof expression</tt><tt>class myStringVector: private Vector&lt;std::string&gt; //base class</tt><tt>{/*...*/};</tt><tt>#include &lt;iostream&gt;</tt><tt>#include &lt;typeinfo&gt;</tt><tt>#include &lt;string&gt;</tt><tt>using namespace std;</tt><tt>cout&lt;&lt;typeid(Vector&lt; string&gt;).name(); //typeid expression</tt><tt>Vector&lt;int&gt; vi; // creating an object</tt></pre><p>The compiler instantiates only the necessary member functions of a given specialization.   In the following example, points of member instantiation are numbered:</p><pre><tt>#include &lt;iostream&gt;</tt><tt>#include "Vector.hpp"</tt><tt>using namespace std;</tt><tt>int main()</tt><tt>{</tt><tt>  Vector&lt;int&gt; vi(5);  // 1</tt><tt>  for (int i = 0; i&lt;5; i++)</tt><tt>  {</tt><tt>    vi[i] = i; //fill vi   // 2</tt><tt>    cout&lt;&lt;vi[i]&lt;&lt;endl;</tt><tt>  }</tt><tt>  return 0;  // 3</tt><tt>}</tt></pre><p>The compiler generates code only for the following <tt>Vector</tt> member functions,   which are used either explicitly or implicitly in the program:</p><pre><tt>Vector&lt;int&gt;::Vector&lt;int&gt; (size_t s) //1: constructor</tt><tt>: sz(s), buff (new int[s]) {}</tt><tt>inline int&amp; Vector&lt;int&gt;::operator [] (unsigned int idx) //2: operator []</tt><tt>{</tt><tt>  return buff[idx];</tt><tt>}</tt><tt>Vector&lt;int&gt;::~Vector&lt;int&gt; () //3: destructor</tt><tt>{</tt><tt>  delete [] buff;</tt><tt>}</tt></pre><p>In contrast, code for the member function <tt>size_t Vector&lt;int&gt;::size()   const</tt> is not generated by the compiler because it is not required. For   some compilers, it might be simpler to instantiate all the class members at   once whether they are needed or not. However, the "generate on demand" policy   is a Standard requirement, and has two functions:</p><ul>  <li>    <p> <b>Efficiency</b> -- It is not uncommon for certain class templates to       define hundreds of member functions (STL containers, for example); normally,       however, fewer than a dozen of these are actually used in a program. Generating       the code for unused member functions times the number of specializations       used in the program can easily bloat the size of the executable -- and it       might unnecessarily increase compilation and linkage time.</p>  </li>  <p></p>  <li>    <p> <b>Flexibility</b> -- In some cases, not every type supports all the operations       that are defined in a class template. For example, a container class can       use <tt>ostream</tt>'s operator <tt>&lt;&lt;</tt> to display members of       fundamental types such as <tt>char</tt> and <tt>int</tt> and user-defined       types for which an overloaded version of <tt>&lt;&lt;</tt> is defined. However,       a POD (plain old data) struct for which no overloaded version of <tt>&lt;&lt;</tt>       exists can still be stored in such a container as long as the <tt>&lt;&lt;</tt>       is not invoked.</p>  </li></ul><p></p><h3> <a name="Heading5">Template Arguments</a></h3><p>A template can take type parameters, that is, symbols that represent an as   yet unspecified type. For example</p><pre><tt>template &lt;class T &gt; class Vector {/*...*/};</tt></pre><p>A template can also take ordinary types such as <tt>int</tt> and <tt>long</tt>   as parameters:</p><pre><tt>template &lt;class T, int n&gt; class Array</tt><tt>{</tt><tt>private:</tt><tt>  T a[n];</tt><tt>  int size;</tt><tt>public:</tt><tt>  Array() : size (n){}</tt><tt>  T&amp; operator [] (int idx) { return a[idx]; }</tt><tt>};</tt></pre><p>Note, however, that when an ordinary type is used as a parameter, the template   argument must be a constant or a constant expression of an integral type. For   example</p><pre><tt>void  array_user()</tt><tt>{</tt><tt>  const int cn = 5;</tt><tt>  int num = 10;</tt><tt>  Array&lt;char, 5&gt; ac;  // OK, 5 is a const</tt><tt>  Array&lt;float, cn&gt; af;  // OK, cn is const</tt><tt>  Array&lt;unsigned char, sizeof(float)&gt; auc;  // OK, constant expression used</tt><tt>  Array&lt;bool,  num&gt; ab;  // error, num is not a constant</tt><tt>}</tt></pre><p>Besides constant expressions, other arguments that are allowed are a non-overloaded   pointer to member and the address of an object or a function with external linkage.   This also implies that a string literal cannot be used as a template argument   because it has internal linkage. For example:</p>

⌨️ 快捷键说明

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