📄 index.html
字号:
<i>abstract data types</i> (not to be confused with <i>abstract classes</i>;
see the sidebar titled "Abstract Data Types Versus Abstract Classes" later in
this chapter). </p>
<p>These classes can meet a vast variety of needs in clean and easy-to-maintain
capsules that separate implementation from interface. C++ provides the necessary
mechanisms for data abstraction in the form of classes, which bundle data with
a full set of associated operations. Information hiding is achieved by means
of the <tt>private</tt> access specifier, which restricts the access to data
members to class members exclusively.</p>
<h4> Operator Overloading</h4>
<p>In object-based languages, the user can extend the definition of a built-in
operator to support a user-defined type (operator overloading is discussed in
Chapter 3, "Operator Overloading"). This feature provides a higher level of
abstraction by rendering user-defined types a status of built-in types. For
example</p>
<pre>
<tt>class Date</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> char day;</tt>
<tt> char month;</tt>
<tt> short year;</tt>
<tt> long secs;</tt>
<tt>public:</tt>
<tt> bool operator < (const Date& other);</tt>
<tt> bool operator == (const Date& other);</tt>
<tt> //...other member functions</tt>
<tt>};</tt>
</pre>
<h4> Characteristics of Object-Based Programming</h4>
<p>In a way, object-based programming can be thought of as a subset of object-oriented
programming; that is, some common principles are adhered to in both paradigms.
Unlike object-oriented programming, however, object-based programming does not
use inheritance. Rather, each user-defined class is a self-contained entity
that is neither derived from a more general type, nor does it serve as a base
for other types. The lack of inheritance in this paradigm is not coincidental.
Proponents of object-based programming claim that inheritance complicates design,
and that it might propagate bugs and deficiencies in a base class to its subclasses.
Furthermore, inheritance also implies polymorphism, which is a source for additional
design complexities. For instance, a function that takes a base object as an
argument also knows how to handle any object that is publicly derived from that
base.</p>
<h4> Advantages of Object-Based Programming</h4>
<p>Object-based programming overcomes most of the shortcomings of procedural programming.
It localizes changes, it decouples implementation details from the interface,
and it supports user-defined types. The Standard Library provides a rich set
of abstract data types, including <tt>string</tt>, <tt>complex</tt>, and <tt>vector</tt>.
These classes are designed to provide an abstraction for very specific uses,
for example, character manipulations and complex numbers arithmetic. They are
not derived from a more general base class, and they are not meant to be used
as a base for other classes.</p>
<blockquote>
<hr>
<b>Abstract Data Types Versus Abstract Classes</b><br>
The terms <i>abstract data type</i> and <i>abstract class </i>refer to two entirely
different concepts, although both of them use the word <i>abstract</i> due to
a historical accident. An abstract data type (also called a <i>concrete type</i>)
is a self-contained, user-defined type that bundles data with a set of related
operations. It behaves in the same way as does a built-in type. However, it
is not extensible nor does it exhibit dynamic polymorphism. In contrast, an
abstract class is anything but an abstract data type. It is not a data type
(normally, abstract classes do not contain any data members), nor can you instantiate
an object thereof. An abstract class is merely a skeletal interface, that specifies
a set of services or operations that other (nonabstract) classes implement.
Unfortunately, the distinction between the two concepts is often confused. Many
people erroneously use the term <i>abstract data type</i> when they are actually
referring to an abstract class.
<hr>
</blockquote>
<h4> Limitations of Object-Based Programming</h4>
<p>Object-based programming is advantageous for specific uses. However, it cannot
capture real-world relationships that exist among objects. The commonality that
exists among a floppy disk and a hard disk, for instance, cannot be expressed
directly in an object-based design. A hard disk and a floppy disk can both store
files; they can contain directories and subdirectories, and so on. However,
the implementer has to create two distinct and autonomous entities in this case,
without sharing any common features that the two have.</p>
<h3> <a name="Heading5">Object-Oriented Programming</a></h3>
<p>Object-oriented programming overcomes the limitations of object-based programming
by providing the necessary constructs for defining <i>class hierarchies</i>.
A class hierarchy captures the commonality among similar -- and yet distinct
-- types. For example, the classes <tt>Mouse</tt> and a <tt>Joystick</tt> are
two distinct entities, yet they share many common features that can be factored
out into a common class, <tt>PointingDevice,</tt> which serves as a base class
for both. Object-oriented programming is based on the foundations of object-based
programming such as information hiding, abstract data typing, and encapsulation.
In addition, it supports inheritance, polymorphism, and dynamic<i> </i>binding.</p>
<h4> Characteristics of Object-Oriented Programming</h4>
<p>Object-oriented programming languages differ from one another, sometimes considerably.
Smalltalk programmers who migrate to C++, for instance, find the differences
between the two languages somewhat daunting. The same can be said, of course,
for C++ programmers who migrate to Smalltalk or Eiffel. However, several common
characteristics that exist in all object-oriented programming languages distinguish
them from non-object-oriented ones. These characteristics are presented in the
following sections.</p>
<p><b>Inheritance</b></p>
<p>Inheritance enables a derived class to <i>reuse</i> the functionality and interface
of its base class. The advantages of reuse are enormous: faster development
time, easier maintenance, and simpler extensibility. The designer of class hierarchies
captures the generalizations and commonality that exist among related classes.
The more general operations are located in classes that appear higher in the
derivation graph. Often, the design considerations are application-specific.
For instance, the classes <tt>Thesaurus</tt> and <tt>Dictionary</tt> might be
treated differently in an online ordering system of a bookstore and a computerized
library of the linguistics department in some university. In the bookstore's
online ordering system, the classes <tt>Thesaurus</tt> and <tt>Dictionary</tt>
can inherit from a common base class called <tt>Item:</tt></p>
<pre>
<tt>#include <string></tt>
<tt>#include <list></tt>
<tt>using namespace std;</tt>
<tt>class Review{/*...*/};</tt>
<tt>class Book</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> string author;</tt>
<tt> string publisher;</tt>
<tt> string ISBN;</tt>
<tt> float list_price;</tt>
<tt> list<Review> readers_reviews;</tt>
<tt>public:</tt>
<tt> Book();</tt>
<tt> const string& getAuthor() const;</tt>
<tt> //...</tt>
<tt>};</tt>
</pre>
<p>Classes <tt>Dictionary</tt> and <tt>Thesaurus</tt> are defined as follows:</p>
<pre>
<tt>class Dictionary : public Book</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> int languages; //bilingual, trilingual etc.</tt>
<tt> //...</tt>
<tt>};</tt>
<tt>class Thesaurus: public Book</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> int no_of_entries;</tt>
<tt>//...</tt>
<tt>};</tt>
</pre>
<p>However, the computerized library of the linguistics department might use a
different hierarchy:</p>
<pre>
<tt>class Library_item</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> string Dewey_classification; </tt>
<tt> int copies;</tt>
<tt> bool in_store;</tt>
<tt> bool can_be_borrowed;</tt>
<tt> string author;</tt>
<tt> string publisher;</tt>
<tt> string ISBN;</tt>
<tt>public:</tt>
<tt> Library_item();</tt>
<tt> const string& getDewey_classification() const;</tt>
<tt> //...</tt>
<tt>};</tt>
<tt>class Dictionary : public Library_item</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> int languages;</tt>
<tt> bool phonetic_transciption;</tt>
<tt> //...</tt>
<tt>};</tt>
<tt>class Thesaurus: public Library_item</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> int entries;</tt>
<tt> int century; //historical period of the language, e.g., Shakespeare's era</tt>
<tt>//...</tt>
<tt>};</tt>
</pre>
<p>These two hierarchies look different because they serve different purposes.
However, the crucial point is that the common functionality and data are "elevated"
to the base class that is extended by more specialized classes. Introducing
a new class, for example <tt>Encyclopedia</tt>, to either the bookstore ordering
system or the computerized library of the linguistics department is much easier
in an object-oriented environment. That is because most of the functionality
of the new class already exists in the base class, whatever it might be. On
the other hand, in an object-based environment, every new class has to be written
from scratch.</p>
<p><b>Polymorphism</b></p>
<p><i>Polymorphism</i> is the capability of different objects to react in an individual
manner to the same message. Polymorphism is widely used in natural languages.
Consider the verb <i>to close</i>: It means different things when applied to
different objects. Closing a door, closing a bank account, or closing a program's
window are all different actions; their exact meaning depends on the object
on which the action is performed. Similarly, polymorphism in object-oriented
programming means that the interpretation of a message depends on its object.
C++ has three mechanisms of static (compile-time) polymorphism: operator overloading,
templates, and function overloading. </p>
<p><b>Operator Overloading</b></p>
<p>Applying operator <tt>+=</tt>, for example, to an <tt>int</tt> or a <tt>string</tt>
is interpreted by each of these objects in an individual manner. Intuitively,
however, you can predict what results will be, and you can find some similarities
between the two. Object-based programming languages that support operator overloading
are, in a limited way, polymorphic as well.</p>
<p><b>Templates</b></p>
<p>A <tt>vector<int></tt> and a <tt>vector<string></tt> react differently;
that is, they execute a different set of instructions when they receive the
same message. However, you can expect similar behavior (templates are discussed
in detail in Chapter 9, "Templates"). Consider the following example:</p>
<pre>
<tt>vector < int > vi; vector < string > names;</tt>
<tt>string name("Bjarne");</tt>
<tt>vi.push_back( 5 ); // add an integer at the end of the vector</tt>
<tt>names.push_back (name); //add a string at the end of the vector</tt>
</pre>
<p><b>Function Overloading</b></p>
<p>Function overloading is a third form of polymorphism. In order to overload
a function, a different list of parameters is used for each overloaded version.
For example, a set of valid overloaded versions of a function named <tt>f()</tt>
might look similar to the following:</p>
<pre>
<tt>void f(char c, int i);</tt>
<tt>void f(int i, char c); //order of parameters is significant</tt>
<tt>void f(string & s);</tt>
<tt>void f();</tt>
<tt>void f(int i);</tt>
<tt>void f(char c);</tt>
</pre>
<p>Note, however, that a function that differs only by its returned type is illegal
in C++:</p>
<pre>
<tt>int f(); //error; differs from void f(); above only by return type</tt>
<tt>int f(float f); //fine - unique signature</tt>
</pre>
<p><b>Dynamic Binding</b></p>
<p><i>Dynamic</i> <i>binding</i> takes the notion of polymorphism one step further.
In dynamic binding, the meaning of a message depends on the object that receives
it; yet, the exact type of the object can be determined only at runtime. Virtual
member functions are a good example of this. The specific version of a virtual
function might not be known at compile time. In this case, the call resolution
is delayed to runtime, as in the following example:</p>
<pre>
<tt>#include <iostream></tt>
<tt>using namespace std;</tt>
<tt>class base</tt>
<tt>{</tt>
<tt> public: virtual void f() { cout<< "base"<<endl;}</tt>
<tt>};</tt>
<tt>class derived : public base</tt>
<tt>{</tt>
<tt> public: void f() { cout<< "derived"<<endl;} //overrides base::f</tt>
<tt>};</tt>
<tt>void identify(base & b) // the argument can be an instance</tt>
<tt> // of base or any object derived from it</tt>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -