The dynamic_cast operator is used to cast a derived class pointer to a base class pointer; its main purpose is to ensure that it's okay to invoke a virtual function call.. .5: Suppose yo
Trang 1compiler to accept the following statement in change():
*pc = 100;
However, because pop2 is declared as const, the compiler may protect it from any
change, as is shown by the following sample output:
pop1, pop2: 38383, 2000
pop1, pop2: 100, 2000
As you can see, the calls to change() altered pop1 but not pop2 (The particular compiler
used here generated a temporary copy of pop2 and assigned that address to pc, but, as
mentioned, the standard says the behavior in this situation is undefined.)
The static_cast operator has the same syntax as the others:
static_cast < type-name > (expression)
It's valid only if type_name can be converted implicitly to the same type expression has,
or vice versa Otherwise, the cast is an error Suppose High is a base class to Low and
that Pond is an unrelated class Then conversions from High to Low and Low to High are
valid, but a conversion from Low to Pond is disallowed:
High bar;
Low blow;
High * pb = static_cast<High *> (&blow); // valid upcast
Low * pl = static_cast<Low *> (&bar); // valid downcast
Pond * pmer = static_cast<Pond *> (&blow); // invalid, Pond unrelated
The first conversion is valid because an upcast can be done explicitly The second
conversion, from a base-class pointer to a derived-class pointer can't be done without an
explicit type conversion But because the type cast in the other direction can be made
without a type cast, it's valid to use a static_cast for a downcast
Similarly, because an enumeration value can be converted to an integral type without a
type cast, an integral type can be converted to an enumeration value with static_cast
Similarly, you can use static_cast to convert double to int, float to long, and the various
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it Thanks
Trang 2other numeric conversions.
The reinterpret_cast operator is for inherently risky type-casts It won't let you cast away
const, but it will do other unsavory things Sometimes a programmer has to do
implementation-dependent, unsavory things, and using the reinterpret_cast operator
makes it simpler to keep track of such acts It has the same syntax as the other three:
reinterpret_cast < type-name > (expression)
Here is a sample use:
struct dat { short a; short b} ;
long value = 0xA224B118;
dat * pd = reinterpret_cast< dat *) (&value);
cout << pd->a; // display first 2 bytes of value
Typically, such casts would be used for low-level, implementation-dependent programming
and would not be portable For example, this code sample produces different output on an
IBM-compatible than it does on a Macintosh because the two systems store the bytes in
multibyte integer types in opposite orders
Summary
Friends allow you to develop a more flexible interface for classes A class can have other
functions, other classes, and member functions of other classes as friends In some cases,
you may need to use forward declarations and to exert care in the ordering of class
declarations and methods in order to get friends to mesh properly
Nested classes are classes declared within other classes Nested classes facilitate the
design of helper classes that implement other classes but needn't be part of a public
interface
The C++ exception mechanism provides a flexible way to deal with awkward programming
events such as inappropriate values, failed I/O attempts, and the like Throwing an
exception terminates the function currently executing and transfers control to a matching
catch block Catch blocks immediately follow a try block, and for an exception to be caught,
the function call that directly or indirectly led to the exception must be in the try block The
program thenexecutes the code in the catch block This code may attempt to fix the
Trang 3problem or it can terminate the program A class can be designed with nested exception
classes that can be thrown when problems specific to the class are detected A function
can include an exception specification identifying those exceptions that can be thrown in
that function Uncaught exceptions (those with no matching catch block) by default,
terminate a program So do unexpected exceptions (those not matching an exception
specification.)
The RTTI (runtime type information) features allow a program to detect the type of an
object The dynamic_cast operator is used to cast a derived class pointer to a base class
pointer; its main purpose is to ensure that it's okay to invoke a virtual function call The
typeid operator returns a type_info object Two typeid return values can be compared to
determine if an object is of a specific type, and the returned type_info object can be used
to obtain information about an object
The dynamic_cast operator, along with static_cast, const_cast, and reinterpret_cast,
provide safer, better-documented type casts than the general cast mechanism
Review Questions
.1: What's wrong with the following attempts at establishing friends?
class snap { friend clasp;
} ; class clasp { } ;
a.
class cuff { public:
void snip(muff &) { } .
} ; class muff { friend void cuff::snip(muff &);
b.
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it Thanks
Trang 4} ;
class muff { friend void cuff::snip(muff &);
} ; class cuff { public:
void snip(muff &) { } .
} ;
c.
.2: You've seen how to create mutual class friends Can you create a more restricted form of friendship in which only some members of class B are friends
to class A and some members of A are friends to B? Explain
.3: What problems might the following nested class declaration have?
class Ribs {
private:
class Sauce {
int soy;
int sugar;
public:
Sauce(int s1, int s2) : soy(s1), sugar(s2) { } } ;
.
} ; 4: How does throw differ from return?
.5: Suppose you have a hierarchy of exception classes derived from a base exception class In what order should you place catch blocks?
Trang 5.6: Consider the Grand, Superb, and Magnificent classes defined in this chapter.
Suppose pg is a type Grand * pointer assigned the address of an object of one
of these three classes and that ps is a type Superb * pointer What is the difference in how the following two code samples behave?
if (ps = dynamic_cast<Superb *>(pg)) ps->say(); // sample #1
if (typeid(*pg) == typeid(Superb)) (Superb *) pg)->say(); // sample #2 7: How is the static_cast operator different from the dynamic_cast operator?
Programming Exercises
1: Modify the Tv and Remote classes as follows:
Make them mutual friends
a.
Add a state variable member to the Remote class that describes whether the remote control is in normal or interactive mode
b.
Add a Remote method that displays the mode
c.
Provide the Tv class with a method for toggling the new Remote member This method should work only if the Tv is in the on state
d.
Write a short program testing these new features
2: Modify Listing 15.10 so that hmean() throws an exception of type hmeanexcp and gmean() throws an exception of type gmeanexcp Both of these exception types are to be classes derived from the exception class provided by the
<exception> header file, and you should overload the what() method for each new class so that the message displayed by what() reports the function name and the nature of the problem Also, upon catching an hmeanexcp exception, This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it Thanks
Trang 6the program should prompt for a new data pair and continue with the loop, while upon catching a gmeanexcp exception, the program should break out of the loop and continue with the code following the loop
CONTENTS
Trang 7Chapter 16 THE string CLASS AND THE
STANDARD TEMPLATE LIBRARY
You will learn about the following in this chapter:
The string Class The auto_ptr Class The Standard Template Library Generic Programming
Function Objects (aka Functors) Algorithms
Other Libraries Summary Review Questions Programming Exercises
By now you are familiar with the C++ goal of reusable code One of the big payoffs is when
you can reuse code written by others That's where class libraries come in There are many
commercially available C++ class libraries, and there also are the libraries that come as
part of the C++ package For example, you've been using the input/output classes
supported by the ostream header file This chapter will look at other reusable code
available for your programming pleasure First, the chapter examines the string class,
which simplifies programming with strings Then it looks at auto_ptr, a "smart pointer"
template class that makes managing dynamic memory a bit easier Finally, it looks at the
Standard Template Library (or STL), a collection of useful templates for handling various
kinds of container objects STL exemplifies a recent programming paradigm called generic
programming
The string Class
Many programming applications need to process strings C provides some support with its
string.h (cstring in C++) family of string functions, and many early C++ implementations
provided home-grown classes to handle strings Chapter 12, "Classes and Dynamic
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it Thanks
Trang 8Memory Allocation," introduced a modest String class to illustrate some aspects of class
design ANSI/ISO C++ itself provides a more powerful version called the string class It is
supported by the string header file.(Note that the string.h and cstring header files support
the C library string functions for C-style strings, not the string class.) The key to using a
class is knowing its public interface, and the string class has an extensive set of methods,
including several constructors, overloaded operators for assigning strings, concatenating
strings, comparing strings, and accessing individual elements, as well as utilities for finding
characters and substrings in a string, and more In short, the string class has lots of stuff
Constructing a String
Let's begin with looking at the string constructors After all, one of the most important
things to know about a class is what your options are when creating objects of that class
Listing 16.1 uses all six of the string constructors (labeled ctor, the traditional C++
abbreviation for constructor) Table 16.1 briefly describes the constructors in the order
used in the program The constructor representations are simplified in that they conceal the
fact that string really is a typedef for a template specialization basic_string<char> and
that they omit an optional argument relating to memory management (This aspect is
discussed later this chapter and in Appendix F, "The String Template Class.") The type
size_type is an implementation-dependent integral type defined in the string header file
The class defines string::npos as the maximum possible length of the string Typically,
this would equal the maximum value of an unsigned int Also, the table uses the common
abbreviation NBTS for null-byte-terminated string, that is, the traditional C string, which is
terminated with a null character
Trang 9Table 16.1 string Class Constructors
string(const char * s) Initializes string object to NBTS pointed to by
s.
string(size_type n, char c) Creates a string object of n elements, each
initialized to the character c.each initialized to the character
string(const string & str, string
size_type pos = 0, size_type n = npos)
Initializes string object to the object str, starting at position pos in str and going to end
of str or using n characters, whichever comes first
string(const char * s, size_type n) Initializes string object to NBTS pointed to by
s and continues for n characters even if that exceeds the size of the NBTS
template<class Iter>
string(Iter begin, Iter end)
Initializes string object to the values in the range [begin, end), where begin and end act like pointers and specify locations; the range includes begin and is up to but not including end
The program also uses the overloaded += operator, which appends one string to another,
the overloaded = operator for assigning one string to another, the overloaded << operator
for displaying a string object, and the overloaded [] operator for accessing an individual
character in a string
// str1.cpp introducing the string class
#include <iostream>
#include <string>
using namespace std;
// using string constructors
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it Thanks
Trang 10int main()
{
string one("Lottery Winner!"); // ctor #1
cout << one << endl; // overloaded <<
string two(20, '$'); // ctor #2
cout << two << endl;
string three(one); // ctor #3
cout << three << endl;
one += " Oops!"; // overloaded +=
cout << one << endl;
two = "Sorry! That was ";
three[0] = 'P';
string four; // ctor #4
four = two + three; // overloaded +, =
cout << four << endl;
char alls[] = "All's well that ends well";
string five(alls,20); // ctor #5
cout << five << "!\n";
string six(alls+6, alls + 10); // ctor #6
cout << six << ", ";
string seven(&five[6], &five[10]);// ctor #6 again
cout << seven << " \n";
return 0;
}
Compatibility Note
Some older string implementations do not support ctor #6
Here is the program's output:
Lottery Winner!
$$$$$$$$$$$$$$$$$$$$
Lottery Winner!
Trang 11Lottery Winner! Oops!
Sorry! That was Pottery Winner!
All's well that ends!
well, well
Program Notes
The start of the program illustrates that you can initialize a string object to a regular C-style
string and display it using the overloaded << operator:
string one("Lottery Winner!"); // ctor #1
cout << one << endl; // overloaded <<
The next constructor initializes the string object two to a string consisting of 20 $
characters:
string two(20, '$'); // ctor #2
The copy constructor initializes the string object three to the string object one:
string three(one); // ctor #3
The overloaded += operator appends the string " Oops!" to the string one:
one += " Oops!"; // overloaded +=
This particular example appends a C-style string to a string object However, the +=
operator is multiply overloaded so that you also can append string objects and single
characters:
one += two; // append a string object (not in program)
one += '!'; // append a type char value (not in program)
Similarly, the = operator is overloaded so that you can assign a string object to a string
object, a C-style string to a string object, or a simple char value to a string object:
two = "Sorry! That was "; // assign a C-style string
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it Thanks