Tải bản đầy đủ (.pdf) (10 trang)

A Complete Guide to Programming in C++ part 48 pot

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (201.81 KB, 10 trang )

EXERCISE

449
Exercise
Enhance the numerical class Fraction, which you know from the last chapter, to
convert both
double values to fractions and fractions to double. In addition,
fractions should be rounded after arithmetic operations.
■ First declare the simplify() method for the Fraction class and insert
the definition on the opposite page in your source code.The method
computes the largest common divisor of numerator and denominator.
The numerator and the denominator are then divided by this value.
■ Add an appropriate call to the simplify() function to all operator func-
tions (except
++ and ).
■ Then add a conversion constructor with a double type parameter to the
class.
Example:
Fraction b(0.5); // yields the fraction 1/2
Double values should be converted to fractions with an accuracy of three
decimal places.The following technique should suffice for numbers below
one million. Multiply the
double value by 1000 and add 0.5 for rounding.
Assign the result to the numerator. Set the value of the denominator to
1000.Then proceed to simplify the fraction.
■ You now have a conversion constructor for long and double types.To
allow for conversion of
int values to fractions, you must write your own
conversion constructor for
int!
■ Now modify the class to allow conversion of a fraction to a double type


number. Define the appropriate conversion function
inline.
Use the function
main() to test various type conversions. More specifically, use
assignments and arithmetic functions to do so.Also compute the sum of a
fraction and a floating-point number.
Output the operands and the results on screen.
solution
450

CHAPTER 20 TYPE CONVERSION FOR CLASSES

SOLUTION
//
// Fraction.h
// A numerical class to represent fractions.
// The class converts Fraction < > double
// and simplifies fractions.
//
#ifndef _FRACTION_
#define _FRACTION_
#include <iostream.h>
#include <stdlib.h>
class Fraction
{
private: long numerator, denominator;
public:
Fraction(long z, long n);
Fraction(double x); // double-constructor
// Default long- and int-constructor:

Fraction(long z=0) : numerator(z), denominator(1) {}
Fraction(int z) : numerator(z), denominator(1) {}
void simplify();
operator double() // Fraction -> double
{
return (double)numerator / (double)denominator;
}
Fraction operator-() const
{ return Fraction(-numerator, denominator); }
Fraction& operator+=(const Fraction& a)
{
numerator = a.numerator * denominator
+ numerator * a.denominator;
denominator *= a.denominator;
simplify();
return *this;
}
Fraction& operator-=(const Fraction& a)
{
*this += (-a); simplify();
return *this;
}
// The rest of the class including methods
// operator++() and operator ()
// and friend declarations are unchanged.
};
#endif
SOLUTION

451

//
// Fraction.cpp
// Defines methods and friend functions
// that are not inline.
//
#include <iostream.h>
#include <stdlib.h>
#include "Fraction.h"
// Constructors:
Fraction::Fraction(long z, long n)
{
// Unchanged! Same as in Chapter 19.
}
Fraction::Fraction( double x)
{
x *= 1000.0;
x += (x>=0.0) ? 0.5 : -0.5; // Round the 4th digit.
numerator = (long)x;
denominator = 1000;
simplify();
}
Fraction operator+(const Fraction& a, const Fraction& b )
{
Fraction temp;
temp.denominator = a.denominator * b.denominator;
temp.numerator = a.numerator*b.denominator
+ b.numerator * a.denominator;
temp.simplify();
return temp;
}

// The functions
// operator-() operator<<() operator>>()
// are left unchanged.
// The functions
// operator*() and operator/()
// are completed by a call to temp.simplify()
// just like the function operator+().
//
// The code of method Fraction::simplify(), as
// specified in the exercise, should be here.
452

CHAPTER 20 TYPE CONVERSION FOR CLASSES
//
// Fract_t.cpp
// Tests the class Fraction with type conversions.
//
#include <iostream.h>
#include "Fraction.h"
int main()
{
Fraction a, b(-1,5), c(2.25);
double x = 0.5, y;
a = x; // double -> Fraction
cout << "\nSome test results:\n" << endl;
cout << " a = " << a << endl;
cout << " b = " << b << endl;
cout << " c = " << c << endl;
cout << "\nThe fractions as double values:\n" << endl;
// Fraction -> double:

cout << " a = " << (double)a << endl;
cout << " b = " << (double)b << endl;
cout << " c = " << (double)c << endl;
cout << "\nAnd calculate with:\n" << endl;
cout << " a + b = " << (a + b) << endl;
cout << " a - b = " << (a - b) << endl;
cout << " a * b = " << (a * b) << endl;
cout << " a / b = " << (a / b) << endl;
cin >> a; // Enter a fraction.
cout << "\nYour input: " << a << endl;
a.simplify();
cout << "\nSimplified: " << a << endl;
cout << "\nAs double value: " << (double)a << endl;
cout << "\nEnter a floating point value: "; cin >> x;
cout << "\nThis is in fraction form: "
<< (Fraction)x << endl;
// To calculate the sum b + x :
cout << " b = " << b << endl;
cout << " x = " << x << endl;
// a = b + x; // Error: ambiguous!
a = b + Fraction(x); // ok! To compute fractions.
y = (double)b + x; // ok! To compute doubles.
cout << " b + x as fraction: " << a << endl;
cout << " b + x as double: " << y << endl;
return 0;
}
453
Dynamic Memory
Allocation
This chapter describes how a program can allocate and release memory

dynamically in line with current memory requirements.
Dynamic memory allocation is an important factor in many C++
programs and the following chapters will contain several additional case
studies to help you review the subject.
chapter
21
454

CHAPTER 21 DYNAMIC MEMORY ALLOCATION
Heap
ptr_long
ptr_double
1234567
1.9
// Dynamic objects of type long and double
//
long *ptr_long;
ptr_long = new long; // No initialization
// of the long object.
*ptr_long = 1234567; // Assign a value
double *ptr_double;
double z = 1.9;
ptr_double = new double(z); // With initialization
++(*ptr_double); // Increment the value
*ptr_double += *ptr_long; // ok to add long value
ptr_long = new double(2.7); // Error: ptr_long not
// pointing to double!

THE OPERATOR new
Sample calls to new

On the heap
THE OPERATOR new

455
ᮀ Dynamic Memory Allocation
When a program is compiled, the size of the data the program will need to handle is
often an unknown factor; in other words there is no way to estimate the memory require-
ments of the program. In cases like this you will need to allocate memory dynamically,
that is, while the program is running.
Dynamically allocated memory can be released to continually optimize memory usage
with respect to current requirements. This in turn provides a high level of flexibility,
allowing a programmer to represent dynamic data structures, such as trees and linked
lists.
Programs can access a large space of free memory known as the heap. Depending on
the operating system (and how the OS is configured), the heap can also occupy large
amounts of unused space on the hard disk by swapping memory to disk.
C++ uses the new and delete operators to allocate and release memory, and this
means that objects of any type can be created and destroyed. Let’s look at the scenario
for fundamental types first.
ᮀ Calling new for Fundamental Types
The new operator is an operator that expects the type of object to be created as an argu-
ment. In its simplest form, a call to new follows this syntax
Syntax: ptr = new type;
Where ptr is a pointer to type. The new operator creates an object of the specified
type and returns the address of that object. The address is normally assigned to a pointer
variable. If the pointer belongs to a wrong type, the compiler will issue an error message.
Example: long double *pld = new long double;
This statement allocates memory for a long double type object, that is,
sizeof(long double) bytes.
The previous call to new does not define an initial value for the new object, however,

you can supply a value in parentheses to initialize the object.
Example: pld = new long double(10000.99);
Following this statement pld points to a memory address containing a long double
type with a value of 10000.99. The statement
cout << *pld << endl;
will output this value.
456

CHAPTER 21 DYNAMIC MEMORY ALLOCATION
// DynStd.cpp
// The operators new and delete for built-in types.
// The program contains errors!
// ==> Save all data before starting.
//
#include <iostream>
using namespace std;
int main()
{
cout << "\nTesting dynamic storage allocation! "
<< endl;
// To allocate storage:
double width = 23.78;
double* ptrWidth = &width;
double* ptrLength = new double(32.54);
double* ptrArea = new double;
// To work with ptrWidth, ptrLength, and ptrArea:
*ptrArea = *ptrWidth * *ptrLength;
delete ptrLength; // Error: The object is still
// in use!
cout << "\nWidth : " << *ptrWidth

<< "\nLength : " << *ptrLength
<< "\nArea : " << *ptrArea << endl;
// To free storage:
delete ptrWidth; // Error: The object has not
// been dynamically reserved
delete ptrLength; // ok
delete ptrArea; // ok
delete ptrLength; // Error: Pointer doesn't
// address any object.
ptrLength = new double(19.45); // ok
// To give a name to a dynamic object:
double& length = *ptrLength; // Reference
cout << "\nNew length : " << length
<< "\nCircumference : " << 2 * width * length
<< endl;
return 0; // On terminating the program
} // allocated storage will be freed.

THE OPERATOR delete
Sample program
THE OPERATOR delete

457
A program should make careful use of available memory and always release memory that
is no longer needed. Failure to do so can impact the performance of your computer sys-
tem. Memory that is released is available for further calls to new.
ᮀ Calling delete
Memory that has been allocated by a call to new can be released using the delete oper-
ator. A call to delete follows this syntax
Syntax: delete ptr;

The operand ptr addresses the memory space to be released. But make sure that this
memory space was dynamically allocated by a call to new!
Example: long *pl = new long(2000000);
. . . . // to work with *pl.
delete pl;
If you do not call delete, the dynamically allocated memory space is not released until
the program terminates.
You can pass a NULL pointer to delete when you call the operator. In this case
nothing happens and delete just returns, so you do not need to check for NULL point-
ers when releasing memory.
A delete expression is always a void type, so you cannot check whether memory
has been successfully released.
As the sample program illustrates, misuse of delete can be disastrous. More specifi-
cally
■ do not call delete twice for the same object
■ do not use delete to release statically allocated memory.
ᮀ Error Handling for new
If there is not enough memory available, the so-called new handler is called. The new
handler is a function designed for central error handling. Thus, you do not need to design
your own error handling routines each time you call new.
The new handler is activated by default and throws an exception. Exceptions can be
caught by the program, allowing the error condition to be remedied (refer to Chapter 28,
Exception Handling). Any exception that is not caught will terminate the program,
however, you can install your own new handler.
If you are working with an older compiler, please note that new returns a NULL
pointer if not enough memory is available.
458

CHAPTER 21 DYNAMIC MEMORY ALLOCATION
// DynObj.cpp

// The operators new and delete for classes.
//
#include "account.h"
#include <iostream>
using namespace std;
Account *clone( const Account* pK); // Create a copy
// dynamically.
int main()
{
cout << "Dynamically created objects.\n" << endl;
// To allocate storage:
Account *ptrA1, *ptrA2, *ptrA3;
ptrA1 = new Account; // With default constructor
ptrA1->display(); // Show default values.
ptrA1->setNr(302010); // Set the other
ptrA1->setName("Tang, Ming"); // values by access
ptrA1->setStand(2345.87); // methods.
ptrA1->display(); // Show new values.
// Use the constructor with three arguments:
ptrA2 = new Account("Xiang, Zhang", 7531357, 999.99);
ptrA2->display(); // Display new account.
ptrA3 = clone( ptrA1); // Pointer to a dyna-
// mically created copy.
cout << "Copy of the first account: " << endl;
ptrA3->display(); // Display the copy.
delete ptrA1; // Release memory
delete ptrA2;
delete ptrA3;
return 0;
}

Account *clone( const Account* pK) // Create a copy
{ // dynamically.
return new Account(*pK);
}

DYNAMIC STORAGE ALLOCATION FOR CLASSES
Sample program

×