1. Trang chủ
  2. » Công Nghệ Thông Tin

A Complete Guide to Programming in C++ part 45 pdf

10 287 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 229,18 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Example: Euro wholesale15,30, retail, profit7,50, discount1,75; retail = wholesale + profit; // Call: wholesale.operator+ profit retail -= discount; // Call: retail.operator-= discount r

Trang 1

䊐 Calling Operator Functions

The following expressions are valid for the operators in the Euroclass

Example: Euro wholesale(15,30), retail,

profit(7,50), discount(1,75);

retail = wholesale + profit;

// Call: wholesale.operator+( profit)

retail -= discount;

// Call: retail.operator-=( discount)

retail += Euro( 1.49);

// Call: retail.operator+=( Euro(1.49))

These expressions contain only Euro type objects, for which operator functions have been defined However, you can also add or subtract intordoubletypes This is made possible by the Euro constructors, which create Euro objects from int or double

types This allows a function that expects a Euro value as argument to process intor

doublevalues

As the program opposite shows, the statement

Example: retail += 9.49;

is valid The compiler attempts to locate an operator function that is defined for both the

Euro object and the double type for += Since there is no operator function with these characteristics, the compiler converts the double value to Euro and calls the existing operator function for euros

䊐 Symmetry of Operands

The available constructors also allow you to call the operator functions of +and – with

intordoubletype arguments

Example: retail = wholesale + 10; // ok

wholesale = retail - 7.99; // ok

The first statement is equivalent to

retail = wholesale.operator+( Euro(10));

But the following statement is invalid!

Example: retail = 10 + wholesale; // wrong!

Since the operator function was defined as a method, the left operand must be a class object Thus, you cannot simply exchange the operands of the operator + However, if you want to convert both operands, you will need global definitions for the operator functions

Trang 2

420 C H A P T E R 1 9 O V E R L O A D I N G O P E R A T O R S

= () []

->

Assignment operator

Function call

Subscript operator

Class member access

The function call operator () is used to represent operations for objects like function calls The overloaded operator ->enables the use of objects in the same way as pointers

NOTE

// Euro.h // The class Euro represents a Euro with // global operator functions implemented for + and -.

//

-#ifndef _EURO_H_

#define _EURO_H_

//

class Euro

{ // Without operator functions for + and -.

// Otherwise unchanged, specifically with regard to // the operator functions implemented for += and -=.

};

// -// Global operator functions (inline)

// Addition:

inline Euro operator+( const Euro& e1, const Euro& e2)

{ Euro temp(e1);

temp += e2;

return temp;

} // Subtraction:

inline Euro operator-( const Euro& e1, const Euro& e2)

{ Euro temp(e1); temp -= e2;

return temp;

}

GLOBAL OPERATOR FUNCTIONS Operators overloadable by methods only

The operator functions of the following operators have to be methods:

The new Euro class

Trang 3

䊐 Operator Functions: Global or Method?

You can define an operator function as a global function instead of a method The four operators listed opposite are the only exceptions

+= -= *= /= %=

These operators always require a so-called l-value as their left operand, that is, they

require an object with an address in memory

Global operator functions are generally preferable if one of the following situations applies:

■ the operator is binary and both operands are symmetrical, e.g the arithmetic operators+or*

■ the operator is to be overloaded for another class without changing that class, e.g the<<operator for the ostreamclass

䊐 Defining Global Operator Functions

The operands for a global operator function are passed as arguments to that function

The operator function of a unary operator thus possesses a single parameter, whereas the operator function of a binary operator has two.

TheEuroclass has been modified to provide a global definition of the operator func-tions for the operators +and-

Example: Euro operator+(const Euro& e1, const Euro& e2);

Both operands are now peers More specifically, conversion of intordoubletoEuro

is performed for both operands now Given a Euroobject net, the following expres-sions are valid and equivalent:

Example: net + 1.20 and 1.20 + net

They cause the following function calls:

operator+( net, 1.20) and

operator+( 1.20, net)

However, a global function cannot access the private members of the class The func-tion operator+() shown opposite therefore uses the += operator, whose operator function is defined as a method

A global operator function can be declared as a “friend” of the class to allow it access

to the private members of that class

Trang 4

422 C H A P T E R 1 9 O V E R L O A D I N G O P E R A T O R S

// Euro.h // The class Euro with operator functions // declared as friend functions

//

-#ifndef _EURO_H_

#define _EURO_H_

//

class Euro {

private:

long data; // Euros * 100 + Cents public:

// Constructors and other methods as before

// Operators -(unary), +=, -= as before

{ // = *this * (1/x) return (*this * (1.0/x));

}

friend Euro operator+( const Euro& e1, const Euro& e2); friend Euro operator-( const Euro& e1, const Euro& e2); friend Euro operator*( const Euro& e, double x)

{ Euro temp( ((double)e.data/100.0) * x) ; return temp;

} friend Euro operator*( double x, const Euro& e) {

return e * x;

} };

// Addition:

inline Euro operator+( const Euro& e1, const Euro& e2) {

Euro temp; temp.data = e1.data + e2.data;

return temp;

} // Subtraction:

inline Euro operator-( const Euro& e1, const Euro& e2) {

Euro temp; temp.data = e1.data - e2.data;

return temp;

}

#endif // _EURO_H_

FRIEND FUNCTIONS

Class Euro with friend functions

Trang 5

䊐 The Friend Concept

If functions or individual classes are used in conjunction with another class, you may want to grant them access to the privatemembers of that class This is made possible

by a friend declaration, which eliminates data encapsulation in certain cases.

Imagine you need to write a global function that accesses the elements of a numerical array class If you need to call the access methods of the class each time, and if these methods perform range checking, the function runtime will increase considerably How-ever, special permission to access the private data members of the class can dramatically improve the function’s response

䊐 Declaring Friend Functions

A class can grant any function a special permit for direct access to its private members This is achieved by declaring the function as a friend The friendkeyword must pre-cede the function prototype in the class definition

Example: class A

{ //

friend void globFunc( A* objPtr);

friend int B::elFunc( const A& objRef);

};

Here the global function globFunc() and the method elFunc() of class B are declared as friendfunctions of class A This allows them direct access to the private members of class A Since these functions are not methods of class A, the thispointer is not available to them To resolve this issue, you will generally pass the object the func-tion needs to process as an argument

It is important to note that the class itself determines who its friends are If this were

not so, data encapsulation could easily be undermined

䊐 Overloading Operators with Friend Functions

The operator functions for +and-in the Euroclass are now defined as friend func-tions, allowing them direct access to the private member data

In order to compute interest, it is necessary to multiply and divide euros by double

values Since both the expression Euro*numandnum*Euroare possible, friend func-tions are implemented to perform multiplicafunc-tions As the example shows, friend func-tions can also be defined inlinein a class

Trang 6

424 C H A P T E R 1 9 O V E R L O A D I N G O P E R A T O R S

// Result.h // The class Result to represent a measurement // and the time the measurement was taken

//

-#ifndef _RESULT_

#define _RESULT_

#include "DayTime.h" // Class DayTime class Result

{ private:

double val;

DayTime time;

public:

// Constructor and access methods

}; // ControlPoint are friends

#include Result.h class ControlPoint {

private:

string name; // Name of control point Result measure[100]; // Table with results //

public:

// Constructor and the other methods //

// Compute static values of measurement results // (average, deviation from mean, )

bool statistic(); // Can access the private

// members of measure[i]

};

FRIEND CLASSES

Class Result

Class ControlPoint

Trang 7

䊐 Declaring Friend Classes

In addition to declaring individual friendfunctions, you can also make entire classes

“friends” of another class All the methods in this “friendly” class automatically become

friendfunctions in the class containing the frienddeclaration

This technique is useful if a class is used in such close conjunction with another class

that all the methods in that class need access to the private members of the other class.

For example, the class ControlPoint uses objects of the Result class Calcula-tions with individual measurements are performed repeatedly In this case, it makes sense

to declare the ControlPointclass as a friend of the Resultclass

Example: class Result

{

// friend class ControlPoint;

};

It is important to note that the ControlPointclass has no influence over the fact that

it is a friend of the Resultclass The Resultclass itself decides who its friends are and who has access to its private members

It does not matter whether a frienddeclaration occurs in the privateorpublic

section of a class However, you can regard a frienddeclaration as an extension of the public interface For this reason, it is preferable to place a frienddeclaration in the

publicarea of a class

䊐 Using Friend Functions and Classes

Using friend functions and friend classes helps you to create efficient programs More specifically, you can utilize global friendfunctions where methods are not suited

to the task in hand Some common uses are global operator functions declared as friend functions

However, extensive use of friendtechniques diffuses the concept of data encapsula-tion Allowing external functions to manipulate internal data can lead to inconsistency, especially if a class is modified or extended in a later version For this reason, you should take special care when using friendtechniques

Trang 8

426 C H A P T E R 1 9 O V E R L O A D I N G O P E R A T O R S

// Array_t.cpp // A simple class to represent an array // with range checking

//

-#include <iostream>

#include <cstdlib> // For exit() using namespace std;

#define MAX 100 class FloatArr {

private:

float v[MAX]; // The array public:

float& operator[](int i);

static int MaxIndex(){ return MAX-1; } };

float& FloatArr::operator[]( int i ) {

if( i < 0 || i >= MAX ) { cerr << "\nFloatArr: Outside of range!" << endl; exit(1);

} return v[i]; // Reference to i-th element }

int main() {

cout << "\n An array with range checking!\n"

<< endl;

int i; // An index

// Fill with random euros: for( i=0; i <= FloatArr::MaxIndex(); ++i)

cout << "\nEnter indices between 0 and "

<< FloatArr::MaxIndex() << "!"

<< "\n (Quit by entering invalid input)"

<< endl;

while( cout << "\nIndex: " && cin >> i ) cout << i << " element: " << random[i];

return 0;

}

OVERLOADING SUBSCRIPT OPERATORS

A class representing arrays

Trang 9

䊐 Subscript Operator

The subscript operator []is normally used to access a single array element It is a binary operator and thus has two operands Given an expression such as v[i], the array name

vwill always be the left operand, whereas the index iwill be the right operand

The subscript operator for arrays implies background pointer arithmetic, for example,

v[i]is equivalent to *(v+i) Thus, the following restrictions apply to non-overloaded index operators:

■ an operand must be a pointer—an array name, for example

■ the other operand must be an integral expression

䊐 Usage in Classes

These restrictions do not apply if the index operator is overloaded for a class You should note, however, that the operator function is always a class method with a parameter for the right operand The following therefore applies:

■ the left operand must be a class object

■ the right operand can be any valid type

■ the result type is not defined

This allows for considerable flexibility However, your overloading should always reflect the normal use of arrays More specifically, the return value should be a reference to an object

Since an index can be of any valid type, the possibilities are unlimited For example,

you could easily define associative arrays, that is, arrays whose elements are referenced by

strings

䊐 Notes on the Sample Program

Range checking is not performed when you access the elements of a normal array An invalid index can thus lead to abnormal termination of an application program How-ever, you can address this issue by defining your own array classes, although this may impact the speed of your programs

The opposite page shows a simple array class definition for floatvalues The sub-script operator []has been overloaded to return a reference to the i-th array element However, when the array is accessed, range checking is performed to ensure that the index falls within given boundaries If an invalid index is found, the program issues an error message and terminates

The class FloatArrarray has a fixed length As we will see, variable lengths are pos-sible using dynamic memory allocation

Trang 10

428 C H A P T E R 1 9 O V E R L O A D I N G O P E R A T O R S

// Euro.h : Class Euro to represent an Euro //

-#ifndef _EURO_H_

#define _EURO_H_

//

class Euro { // The class is left unchanged

// The print() method is now superfluous

};

// -// Declaration of shift operators:

ostream& operator<<(ostream& os, const Euro& e);

istream& operator>>(istream& is, Euro& e);

#endif // _EURO_H_

// Euro_io.cpp // Overload the shift operators // for input/output of Euro type objects

//

-#include "Euro.h"

#include <iostream>

using namespace std;

// Output to stream os

ostream& operator<<(ostream& os, const Euro& e) {

os << e.asString() << " Euro"; return os;

} // Input from stream is

istream& operator>>(istream& is, Euro& e) {

cout << "Euro amount (Format x,xx): ";

int euro = 0, cents = 0; char c = 0;

if( !(is >> euro >> c >> cents)) // Input

return is;

if( (c != ',' && c != '.')

|| cents>=100) // Error?

is.setstate( ios::failbit); // Yes => Set else // fail bit

e = Euro( euro, cents); // No => Accept return is; // value

}

OVERLOADING SHIFT-OPERATORS FOR I/O Declaration of the operator functions

Definition of operator functions

Ngày đăng: 06/07/2014, 17:21

TỪ KHÓA LIÊN QUAN