📄 index.html
字号:
</font>
<hr><h2><font color="#009999">21.3 Virtual and Nonvirtual Overriding
(cont.)</font></h2>
<font size="+1">
<ul>
<li>Better:</li>
</ul>
<blockquote>
<pre>class Employee
{
. . .
virtual void print(ostream& out) const;
};
void Employee::print(ostream& out) const
{
out << "Employee " << name();
}</pre>
</blockquote>
</font>
<hr><h2><font color="#009999">21.3 Virtual and Nonvirtual Overriding
(cont.)</font></h2>
<font size="+1">
<blockquote>
<pre>class Manager : public Employee
{
. . .
virtual void print(ostream& out) const;
};
void Manager::print(ostream& out) const
{
out << "Manager " << name();
}
ostream& operator<<(ostream& out, const Employee& e)
{
e.print(out);
return out;
}</pre>
</blockquote>
</font>
<hr><h2><font color="#009999">21.3 Virtual and Nonvirtual Overriding
(cont.)</font></h2>
<font size="+1">
<ul>
<li>One <tt>operator<<</tt>, takes a reference to a base class</li>
<li>Uses a reference selector to call the virtual print method:
<blockquote><tt>
Employee* emp = new Employee("Fred Jones", 67000);<br>
cout << emp << "\n";
</tt></blockquote>
prints: <tt>Employee Fred Jones.</tt>
<blockquote><tt>
emp = new Manager("Sarah Smith", 82000);<br>
cout << emp << "\n";
</tt></blockquote>
prints: <tt>Manager Sarah Smith.</tt>
</li>
</ul>
</font>
<hr><h2><font color="#009999">21.3 Virtual and Nonvirtual Overriding -
wrapup</font></h2>
<font size="+1">
<dl>
<dt>Retain the <tt>virtual</tt> Keyword</dt>
<dd>Once declared <tt>virtual</tt>, a method remains virtual in all
derived classes</dd>
<dt>Heterogeneous Collections</dt>
<dd>A vector of pointers can store values of any derived type</dd>
<dt>Include Virtual Destructors</dt>
<dd>If a class has a virtual method, define a virtual d'tor</dd>
</dl>
</font>
<hr><h2><font color="#009999">21.4 Pure Virtual Member Functions</font></h2>
<font size="+1">
<ul>
<li><i>abstract class</i>: contains a pure virtual method</li>
<li>Provides an i/f, but no behavior</li>
<li>Cannot be instantiated</li>
<li>Used only as a base class for inheritance</li>
<li>E.g., compute the area of a shape:
<ul>
<li><tt>Shape</tt> must declare an <tt>area</tt> method</li>
<li>Can't define it</li>
<li>Each derived class has an <tt>area</tt> method</li>
</ul>
</li>
<li><i>interface</i> - class where <i>all</i> methods are pure virtual</li>
</ul>
</font>
<hr><h2><font color="#009999">21.4 Pure Virtual Member Functions
(cont.)</font></h2>
<font size="+1">
<table width='100%' border="1" cellpadding="4" bgcolor="#00cccc">
<tr>
<td bgcolor="#ffffff"><font size="+1"><font color="#009999">Syntax 21.1:
Pure Virtual Member Function</font>
<pre>class <i>ClassName</i>
{
. . .
<font color="#009999">virtual <i>return_type</i> <i>function_name</i>(<i>parameters</i>) = 0;</font>
. . .
};</pre>
<table border="0" cellpadding="4">
<tr>
<td valign="top"><font size="+1" color="#009999">
Example:</font></td>
<td><font size="+1">
<pre>class Shape
{
. . .
virtual double area() const = 0;
};</pre>
</font>
</td>
</tr>
</table>
</td>
</tr>
</table>
</font>
<hr><h2><font color="#009999">21.4 Pure Virtual Member Functions
(cont.)</font></h2>
<font size="+1">
<table border="1" cellpadding="4" bgcolor="#00cccc">
<tr>
<td bgcolor="#ffffff"><font size="+1"><font color="#009999">Syntax 21.1:
Pure Virtual Member Function (cont.)</font>
<table>
<tr>
<td valign="top"><font size="+1" color="#009999">Purpose:</font></td>
<td><font size="+1">Declare a member function with no definition. A
class that contains at least one pure virtual function is termed
abstract. Derived classes must either override the function and
provide their own definition or they themselves will be
considered abstract.</font></td>
</tr>
</table>
</font>
</td>
</tr>
</table>
</font>
<hr><h2><font color="#009999">21.5 Obtaining Run-Time Typing
Information (RTTI)</font></h2>
<font size="+1">
<p>2 common ways to obtain the dynamic type of an object:</p>
<ol>
<li><i>dynamic cast</i> - for casting <i>down</i> the inheritance
hierarchy, checking for success</li>
<li>Using the <tt>type_id</tt> operator to compare a dynamic type
to a known type</li>
</ol>
<p><font color="#009999">Warning:</font> use virtual methods instead of RTTI
and complex conditionals</p>
</font>
<hr><h2><font color="#009999">21.5 (cont.) RTTI - the Dynamic Cast</font></h2>
<font size="+1">
<table border="1" cellpadding="4" bgcolor="#00cccc">
<tr>
<td bgcolor="#ffffff"><font size="+1"><font color="#009999">Syntax 21.2:
Dynamic Cast</font>
<pre>dynamic_cast<<i>type_name</i>>(<i>expression</i>)</pre>
<table border="0" cellpadding="4">
<tr>
<td valign="top"><font size="+1" color="#009999">
Example:</font></td>
<td><font size="+1">
<pre>Employee* e = new Manager("Sarah Smith", 67000, 2000);
Manager* m = dynamic_cast<Manager*>(e);</pre>
</font>
</td>
</tr>
<tr>
<td valign="top"><font size="+1" color="#009999">Purpose:</font></td>
<td><font size="+1">Safely test the type of a polymorphic variable,
converting to a derived class type if appropriate, returning a
<tt>Null</tt> pointer if not.</font></td>
</tr>
</table>
</font>
</td>
</tr>
</table>
</font>
<hr><h2><font color="#009999">21.5 (cont.) RTTI - the Dynamic Cast</font></h2>
<font size="+1">
<ul>
<li>For casting <i>down</i> the inheritance hierarchy.</li>
<li>Takes a pointer or reference</li>
<li>Returns the dynamic type of the argument, if it matches the type
parameter</li>
<li>Otherwise, returns <tt>NULL</tt> (for pointer), or throws
<tt>bad_cast</tt></li>
<li><tt>static_cast</tt> performs no run-time check</li>
</ul>
</font>
<hr><h2><font color="#009999">21.5 (cont.) RTTI - the Dynamic Cast</font></h2>
<font size="+1">
<ul>
<li>Check return type to test type:
</li>
</ul>
<blockquote>
<pre>for (int i = 0; i < department.size(); i++)
{
Manager* m = dynamic_cast<Manager*>(department[i]);
if (m != NULL)
cout << "Employee " << department[i]->get_name()
<< " is a manager.\n";
else
cout << "Employee " << department[i]->get_name()
<< " is not a manager.\n";
}</pre>
</blockquote>
</font>
<hr><h2><font color="#009999">21.5.1 The <tt>typeid</tt> Operator</font></h2>
<font size="+1">
<table border="1" cellpadding="4" bgcolor="#00cccc">
<tr>
<td bgcolor="#ffffff"><font size="+1"><font color="#009999">Syntax 21.3:
<tt>typeid</tt></font>
<pre>typeid(<i>expression</i>)
typeid(<i>type_name</i>)</pre>
<table border="0" cellpadding="4">
<tr>
<td valign="top"><font size="+1" color="#009999">
Example:</font></td>
<td><font size="+1">
<pre>#include <typeinfo>
typeid(*department[i]).name();
if (typeid(*department[i]) == typeid(Manager)) . . .</pre>
</font>
</td>
</tr>
<tr>
<td valign="top"><font size="+1" color="#009999">Purpose:</font></td>
<td><font size="+1">Obtain dynamic type information from a polymorphic
expression.</font></td>
</tr>
</table>
</font>
</td>
</tr>
</table>
</font>
<hr><h2><font color="#009999">21.5.1 The <tt>typeid</tt> Operator (cont.)
</font></h2>
<font size="+1">
<ul>
<li>More general facility</li>
<li>Takes either an expression or a class name (type)</li>
<li>Returns a <tt>type_info</tt>, defined in <tt><typeinfo></tt></li>
</ul>
</font>
<hr><h2><font color="#009999">21.5.1 The <tt>typeid</tt> Operator (cont.)
</font></h2>
<font size="+1">
<ul>
<li>Contains class name, as a string:
<blockquote>
<pre>for (int i = 0; i < department.size(); i++)
cout << typeid(*department[i]).name() << "\n";</pre>
</blockquote>
will produce
<blockquote><tt>
Manager
<br>Employee
<br>Employee
</tt></blockquote>
</li>
</ul>
</font>
<hr><h2><font color="#009999">21.5.1 The <tt>typeid</tt> Operator (cont.)
</font></h2>
<font size="+1">
<ul>
<li>Another way to test an object's type</li>
<li>Compare its <tt>typeinfo</tt> value to that of a known type:
<blockquote>
<pre>
for (int i = 0; i < department.size(); i++)
{
if (typeid(*department[i]) == typeid(Manager))
cout << "Employee " << department[i]->get_name()
<< " is a manager. \n";
else
cout << "Employee " << department[i]->get_name()
<< " is not a manager. \n";
}</pre>
</blockquote>
</li>
<li><font color="#009999">Warning:</font> Comparisons between types and
pointers will always fail</li>
</ul>
</font>
<hr><h2><font color="#009999">21.6 Slicing and Polymorphism</font></h2>
<font size="+1">
<ul>
<li>Layout of objects on the stack is determined at compile time</li>
<li>C++ used different rules for pointers than for objects</li>
<li>Only pointers (and references) are truly polymorphic:
<blockquote>
<pre>Employee e("Lisa Lim", 36000);
Manager m("Sarah Smith", 67000, 2000);
e = m; <font color="#0000cc">// Permitted, but manager fields sliced away</font>
cout << e.annual_income() << "\n";
<font color="#0000cc">// Uses Employee member function</font></pre>
</blockquote>
</li>
</ul>
</font>
<hr><h2><font color="#009999">21.7 Muliple Inheritance</font></h2>
<font size="+1">
<ul>
<li>The real world is not so neatly categorized</li>
<li>Consider a class <tt>TeachingAssistant</tt>
<ul>
<li>Exhibits characteristics of both <tt>Employee</tt> and
<tt>Student</tt>
</ul>
</li>
<li>C++ provides for <i>multiple inheritance</i>:</li>
</ul>
</font>
<hr><h2><font color="#009999">21.7 Muliple Inheritance (cont.)</font></h2>
<font size="+1">
<script><!--
image( "fig06.png" )
//--></script>
<ul>
<li><i>Directed acyclic graph</i>: a class cannot be an ancestor of
itself</li>
</ul>
</font>
<hr><h2><font color="#009999">21.7 Muliple Inheritance (cont.)</font></h2>
<font size="+1">
<table border="1" cellpadding="4" bgcolor="#00cccc">
<tr>
<td bgcolor="#ffffff"><font size="+1"><font color="#009999">Syntax 21.4:
Multiple Inheritance</font>
<pre>class <i>DerivedClassName</i> : public BaseClass</i><sub>1</sub>, . . . public BaseClass<sub>n</sub></i></pre>
<table border="0" cellpadding="4">
<tr>
<td valign="top"><font size="+1" color="#009999">
Example:</font></td>
<td><font size="+1">
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -