[ Pobierz całość w formacie PDF ]
overloading in a way that was revolutionary back in the mid-1950s. For the first time,
built-in operators such as + or - could be applied to various data types: integers, real and
complex. Until then, assembly languages -- which didn't even support operator notation --
had been the only choice for programmers. Fortran's operator overloading was limited to
a fixed set of built-in data types; they could not be extended by the programmer. Object-
based programming languages offered user-defined overloaded operators. In such
languages, it is possible to associate a set of operators with a user-defined type. Object-
oriented languages usually incorporate operator overloading as well.
The capability to redefine the meaning of a built-in operator in C++ was a source of
criticism. People -- mostly C programmers making the migration to C++ -- felt that
overloading an operator was as dangerous as enabling the programmer to add, remove, or
change keywords of the language. Still, notwithstanding the potential Tower of Babel that
might arise as a result, operator overloading is one of the most fundamental features of
C++ and is mandatory for generic programming (generic programming is discussed in
Chapter 10, "STL and Generic Programming."). Today, even languages that tried to make
do without operator overloading are in the process of adding this feature.
This chapter explores the benefits as well as the potential problems of operator
overloading. It also discusses the few restrictions that apply to operator overloading.
Finally, it presents conversion operators, which are a special form of overloaded
operators.
An overloaded operator is essentially a function whose name is an operator preceded by
the keyword operator. For example
class Book
{
private:
long ISBN;
public:
//...
long get_ISBN() const { return ISBN;}
};
bool operator
{
return b1.get_ISBN()
}
Operator Overloading Rules of Thumb
C++ enforces few restrictions on operator overloading. For instance, it does not prohibit a
programmer from overloading the operator ++ in order to perform a decrement operation
on its object (to the dismay of its users, who would instead expect operator ++ to perform
an increment operation). Such misuses and puns can lead to a cryptic coding style that is
almost unintelligible. Often, the source code that contains the definition of an overloaded
operator is not accessible to its users; therefore, overloading an operator in an
unexpected, nonintuitive manner is not recommended.
The other extreme, avoiding operator overloading altogether, is not a practical choice
either because it means giving up an important tool for data abstraction and generic
programming. When you are overloading an operator to support a user-defined type,
therefore, it is recommended that you adhere to the basic semantics of the corresponding
built-in operator. In other words, an overloaded operator has the same side effects on its
operands and manifests the same interface as does the corresponding built-in operator.
Members and Nonmembers
Most of the overloaded operators can be declared either as nonstatic class members or as
nonmember functions. In the following example, the operator == is overloaded as a
nonstatic class member:
class Date
{
private:
int day;
int month;
int year;
public:
bool operator == (const Date & d ); // 1: member function
};
Alternatively, it can be declared as a friend function (the criteria for choosing between a
member and a friend will be discussed later in this chapter):
bool operator ==( const Date & d1, const Date& d2); // 2: nonmember
function
class Date
{
private:
int day;
int month;
int year;
public:
friend bool operator ==( const Date & d1, const Date& d2);
};
Nonetheless, the operators [], (), =, and -> can only be declared as nonstatic member
functions; this ensures that their first operand is an lvalue.
Operator's Interface
When you overload an operator, adhere to the interface of its built-in counterpart. The
interface of an operator consists of the number of operands to which it applies, whether
any of these operands can be altered by the operator, and the result that is returned by the
operator. For example, consider operator ==. Its built-in version can be applied to a wide
variety of fundamental types, including int, bool, float, and char, and to pointers. The
underlying computation process that is required for testing whether the operands of
operator == are equal is an implementation-detail. However, it can be generalized that the
built-in == operator tests its left and right operands for equality and returns a bool value
as its result. It is important to note also that operator == does not modify any of its
operands; in addition, the order of the operands is immaterial in the case of operator ==.
An overloaded operator == should conform to this behavior, too.
Operator Associativity
Operator == is binary and symmetrical. An overloaded version of == conforms to these
qualities. It takes two operands, which are of the same type. Indeed, one can use operator
== to test the equality of two operands of distinct fundamental types, for example char
and int. However, C++ automatically applies integral promotion to the operands in this
[ Pobierz całość w formacie PDF ]
© 2009 ...coś się w niej zmieniło, zmieniło i zmieniało nadal. - Ceske - Sjezdovky .cz. Design downloaded from free website templates