📄 index.html
字号:
<!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 5 - Object-Oriented Programming and Design</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">5</H1>
<h1 align="center"> Object-Oriented Programming and Design</h1>
<address>by Danny Kalev </address>
<ul>
<li><a href="#Heading1">Introduction</a>
<li><a href="#Heading2">Programming Paradigms</a>
<ul>
<li><a href="#Heading3">Procedural Programming</a>
<li><a href="#Heading4">Object-Based Programming</a>
<li><a href="#Heading5">Object-Oriented Programming</a>
</ul>
<li><a href="#Heading6">Techniques Of Object-Oriented Programming</a>
<ul>
<li><a href="#Heading7">Class Design</a>
<li><a href="#Heading8">The "Resource Acquisition Is Initialization" Idiom</a>
</ul>
<li><a href="#Heading9">Classes and Objects</a>
<li><a href="#Heading10">Designing Class Hierarchies</a>
<ul>
<li><a href="#Heading11">Private Data Members Are Preferable To Protected
Ones</a>
<li><a href="#Heading12">Declaring Virtual Base Class Destructors</a>
<li><a href="#Heading13">Virtual Member Functions</a>
<li><a href="#Heading14">Abstract Classes and Interfaces</a>
<li><a href="#Heading15">Use Derivation Instead of Type-Fields</a>
<li><a href="#Heading16">Overloading A Member Function Across Class Boundaries</a>
<li><a href="#Heading17">Deciding Between Inheritance and Containment</a>
<li><a href="#Heading18">The Holds-a Relation</a>
<li><a href="#Heading19">Empty Classes</a>
<li><a href="#Heading20">Using structs as A Shorthand for Public Classes</a>
<li><a href="#Heading21">Friendship</a>
<li><a href="#Heading22">Nonpublic Inheritance</a>
<li><a href="#Heading23">Common Root Class</a>
<li><a href="#Heading24">Forward Declarations</a>
<li><a href="#Heading25">Local Classes</a>
<li><a href="#Heading26">Multiple Inheritance</a>
</ul>
<li><a href="#Heading27">Conclusions</a>
</ul>
<hr size=4>
<h2> <a name="Heading1">Introduction</a></h2>
<p>C++ is the most widely used object-oriented programming language today. The
success of C++ has been a prominent factor in making object-oriented design
and programming a de facto standard in today's software industry. Yet, unlike
other object-oriented programming languages (some of them have been around for
nearly 30 years), C++ does not enforce object-oriented programming -- it can
be used as a "better C", as an <i>object-based</i> language, or as a generic
programming language. This flexibility, which is unparalleled among programming
languages, makes C++ a suitable programming language in any domain area -- real
time, embedded systems, data processing, numerical computation, graphics, artificial
intelligence, or system programming.</p>
<p>This chapter begins with a brief survey of the various programming styles that
are supported by C++. Next, you will focus on various aspects of object-oriented
design and programming.</p>
<h2> <a name="Heading2">Programming Paradigms</a></h2>
<p>A programming paradigm defines the methodology of designing and implementing
software, including the building blocks of the language, the interaction between
data structures and the operations applied to them, program structure, and how
problems are generally analyzed and solved. A programming language provides
the linguistic means (keywords, preprocessor directives, program structure)
as well as the extra-linguistic capabilities, namely standard libraries and
programming environment, to support a specific programming paradigm. Usually,
a given programming language is targeted for a specific application domain,
for example, string manipulation, mathematical applications, simulations, Web
programming and so on. C++, however, is not confined to any specific application
domain. Rather, it supports many useful programming paradigms. Now, for a discussion
of some of the most prominent programming paradigms supported in C++.</p>
<h3> <a name="Heading3">Procedural Programming</a></h3>
<p>C++ is a superset of ISO C. As such, it can be used as a procedural programming
language, albeit with tighter type checking and several enhancements that improve
design and coding: reference variables, inline functions, default arguments,
and <tt>bool</tt> type. Procedural programming is based on separation between
functions and the data that they manipulate. In general, functions rely on the
physical representation of the data types that they manipulate. This dependency
is one of the most problematic aspects in the maintenance and extensibility
of procedural software.</p>
<h4> Procedural Programming Is Susceptible To Design Changes</h4>
<p>Whenever the definition of a type changes (as a result of porting the software
to a different platform, changes in the customer's requirement, and so on),
the functions that refer to that type have to be modified accordingly. The opposite
is also true: When a function is being changed, its arguments might be affected
as well; for instance, instead of passing a struct by value, it might be passed
by address to optimize performance. Consider the following:</p>
<pre>
<tt>struct Date //pack data in a compact struct</tt>
<tt>{</tt>
<tt> char day;</tt>
<tt> char month;</tt>
<tt> short year;</tt>
<tt>};</tt>
<tt>bool isDateValid(Date d); //pass by value</tt>
<tt>void getCurrentDate(Date * pdate); //changes its argument, address needed</tt>
<tt>void initializeDate (Date* pdate); //changes its argument, address needed</tt>
</pre>
<p>Data structures, such as <tt>Date</tt>, and the group of associated functions
that initialize, read, and test it are very common in software projects in which
C is the predominant programming language. Now suppose that due to a change
in the design, <tt>Date</tt> is required to also hold the current time stamp
in seconds. Consequently, a change in the definition of <tt>Date</tt> is made:</p>
<pre>
<tt>struct Date</tt>
<tt>{</tt>
<tt> char day;</tt>
<tt> char month;</tt>
<tt> short year;</tt>
<tt> long seconds;</tt>
<tt>}; //now less compact than before</tt>
</pre>
<p>All the functions that manipulate <tt>Date</tt> have to be modified to cope
with change. An additional change in the design adds one more field to store
millionths of a second in order to make a unique timestamp for database transactions.
The modified <tt>Date</tt> is now</p>
<pre>
<tt>struct Date</tt>
<tt>{</tt>
<tt> char day;</tt>
<tt> char month;</tt>
<tt> short year;</tt>
<tt> long seconds;</tt>
<tt> long millionths;</tt>
<tt>};</tt>
</pre>
<p>Once more, all the functions that manipulate <tt>Date</tt> have to be modified
to cope with the change. This time, even the interface of the functions changes
because <tt>Date</tt> now occupies at least 12 bytes. Functions that are passed
a <tt>Date</tt> by value are modified to accept a pointer to <tt>Date</tt>.</p>
<pre>
<tt>bool isDateValid(Date* pd); // pass by address for efficiency</tt>
</pre>
<h4> Drawbacks of Procedural Programming</h4>
<p>This example is not fictitious. Such frequent design changes occur in almost
every software project. The budget and time overhead that are produced as a
result can be overwhelming; indeed, they sometimes lead to the project's discontinuation.
The attempt to avoid -- or at least to minimize -- these overheads has led to
the emergence of new programming paradigms.</p>
<p>Procedural programming enables only a limited form of code reuse, that is,
by calling a function or using a common user-defined data structure. Nonetheless,
the tight coupling between a data structure and the functions that manipulate
it considerably narrows their reusability potential. A function that computes
the square root of a <tt>double</tt> cannot be applied to a user-defined <tt>struct</tt>
that represents a <tt>complex</tt>, for example. In general, procedural programming
languages rely on static type checking, which ensures better performance than
dynamic type checking -- but it also compromises the software's extensibility.</p>
<p>Procedural programming languages provide a closed set of built-in data types
that cannot be extended. User-defined types are either unsupported or they are
"second class citizens" in the language. The user cannot redefine built-in operators
to support them. Furthermore, the lack of abstraction and information hiding
mechanisms force users to expose the implementation details. Consider the standard
C functions <tt>atof()</tt>, <tt>atoi()</tt>, and <tt>atol()</tt>, which convert
a C-string to <tt>double</tt>, <tt>int</tt>, and <tt>long</tt>, respectively.
Not only do they force the user to pay attention to the physical data type of
the return value (on most machines these days, an <tt>int</tt> and a <tt>long</tt>
are identical anyway), they also prohibit the use of other data types.</p>
<h4> Why Procedural Programming Still Matters</h4>
<p>In spite of its noticeable drawbacks, procedural programming is still the preferred
programming paradigm in some specific application domains, such as embedded
and time critical systems. Procedural programming is also widely used in machine
generated code because code reuse, extensibility, and maintenance are immaterial
in this case. Many SQL interpreters, for example, translate the high-level SQL
statements into C code that is then compiled.</p>
<p>Procedural programming languages -- such as C, Pascal, or Fortran -- produce
the most efficient machine code among high-level programming languages. In fact,
development teams that are reluctant to adopt object orientation often point
to performance degradation as the major deterring factor.</p>
<p>The evolution of C++ is unique among programming languages. The job of its
creators might have been a lot easier had they chosen to design it from scratch,
without guaranteeing backward compatibility with C. Yet this backward compatibility
is one of the its strengths: It enables organizations and programmers to benefit
from C++ without having to trash hundreds of millions of lines of working C
code. Furthermore, C programmers can easily become productive in C++ even before
they have fully mastered object-oriented programming.</p>
<h3> <a name="Heading4">Object-Based Programming</a></h3>
<p>The limitations of procedural programming have led researchers and developers
alike to find better methods of separating implementation details from interfaces.
Object-based programming enables them to create user-defined types that behave
like first class citizens. User-defined types can bundle data and meaningful
operations in a single entity -- a <i>class</i>. Classes also support information
hiding, thereby separating implementation details such as physical representation
and underlying bookkeeping from the set of services that a class provides, or
its <i>interface</i>. Users of a class are allowed to access its interface,
but they cannot access its implementation details. The separation between the
implementation -- which might vary rather frequently due to design changes,
portability, and efficiency -- and the stable interface is substantial. This
separation ensures that changes in the design are localized to a single entity
-- the class implementation; the class users, on the other hand, are not affected.
To assess the importance of object-based programming, examine a simple minded
<tt>Date</tt> class:</p>
<pre>
<tt>class Date</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> char day;</tt>
<tt> char month;</tt>
<tt> short year;</tt>
<tt>public:</tt>
<tt> bool isValid();</tt>
<tt> Date getCurrent();</tt>
<tt> void initialize();</tt>
<tt>};</tt>
</pre>
<h4> Object-Based Programming Localizes Changes In Implementation Details</h4>
<p>Now suppose that you have to change the definition of <tt>Date</tt> to support
time:</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 isValid();</tt>
<tt> Date getCurrent();</tt>
<tt> void initialize ();</tt>
<tt>};</tt>
</pre>
<p>The addition of a new data member does not affect the interface of <tt>Date</tt>.
The users of <tt>Date</tt> don't even know that a new field has been added;
they continue to receive the same services from the class as before. Of course,
the implementer of <tt>Date</tt> has to modify the code of the member functions
to reflect the change. Therefore, <tt>Date::initialize()</tt> has to initialize
one more field. Still, the change is localized only to the definition of <tt>Date::initialize()</tt>
because users cannot access the underlying representation of <tt>Date</tt>.
In procedural programming, however, users can access the data members of <tt>Date</tt>
directly.</p>
<h4> Abstract Data Types</h4>
<p>Classes such as <tt>Date</tt> are sometimes called <i>concrete types,</i> or
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -