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

ANSI/ISO C++ Professional Programmer''''s Handbook phần 3 ppt

24 241 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 24
Dung lượng 68,68 KB

Nội dung

ANSI/ISO C++ Professional Programmer's Handbook - Chapter - Operator Overloading Secondly, a conversion operator takes no arguments Conversion operators can convert their object to any given type, fundamental and user-defined alike: struct DateRep //legacy C code { char day; char month; short year; }; class Date // object-oriented wrapper { private: DateRep dr; public: operator DateRep () const { return dr;} // automatic conversion to DateRep }; extern "C" int transmit_date(DateRep); // C-based communication API function int main() { Date d; // use d //transmit date object as a binary stream to a remote client int ret_stat = transmit_date; //using legacy communication API return 0; } Standard Versus User-Defined Conversions The interaction of a user-defined conversion with a standard conversion can cause undesirable surprises and side effects, and therefore must be used with caution Examine the following concrete example A non-explicit constructor that takes a single argument is also a conversion operator, which casts its argument to an object of this class When the compiler has to resolve an overloaded function call, it takes into consideration such user-defined conversions in addition to the standard ones For example class Numeric { private: float f; public: Numeric(float ff): f(ff) {} //constructor is also a float-to-Numeric // conversion operator }; void f(Numeric); Numeric num(0.05); f(5.f); //OK, calls void f(Numeric) Numeric's constructor //converts argument to a Numeric object 'Suppose you add, at a later stage, another overloaded version of f(): file:///D|/Cool Stuff/old/ftp/1/1/ch03/ch03.htm (8 von 15) [12.05.2000 14:45:47] ANSI/ISO C++ Professional Programmer's Handbook - Chapter - Operator Overloading void f (double); Now the same function call resolves differently: f(5.f); // now calls f(double), not f(Numeric) This is because float is promoted to double automatically in order to match an overloaded function signature This is a standard type conversion On the other hand, the conversion of float to Numeric is a user-defined conversion User-defined conversions rank lower than standard conversions -in overload resolution; as a result, the function call resolves differently Because of this phenomenon and others, conversion operators have been severely criticized Some programming schools ban their usage altogether However, conversion operators are a valuable and sometimes inevitable tool for bridging between dual interfaces, as you have seen Postfix and Prefix Operators For primitive types, C++ distinguishes between ++x; and x++; as well as between x; and x ; Under some circumstances, objects have to distinguish between prefix and postfix overloaded operators as well (for example, as an optimization measure See Chapter 12, "Optimizing Your Code") Postfix operators are declared with a dummy int argument, whereas their prefix counterparts take no arguments For example class Date { public: Date& operator++(); //prefix Date& operator (); //prefix Date& operator++(int unused); //postfix Date& operator (int unused); //postfix }; void f() { Date d, d1; d1 = ++d;//prefix: first increment d and then assign to d1 d1 = d++; //postfix; first assign, increment d afterwards } Using Function Call Syntax An overloaded operator call is merely "syntactic sugar" for an ordinary function call You can use the explicit function call instead of the operator syntax as follows: bool operator==(const Date& d1, const Date& d2); void f() { Date d, d1; bool equal; d1.operator++(0); // equivalent to: d1++; d1.operator++(); // equivalent to: ++d1; equal = operator==(d, d1);// equivalent to: d==d1; file:///D|/Cool Stuff/old/ftp/1/1/ch03/ch03.htm (9 von 15) [12.05.2000 14:45:47] ANSI/ISO C++ Professional Programmer's Handbook - Chapter - Operator Overloading Date&(Date::*pmf) (); //pointer to member function pmf = & Date::operator++; } Consistent Operator Overloading Whenever you overload operators such as + or -, it might become necessary to support the corresponding += and -= operators as well The compiler does not that for you automatically Consider the following example: class Date { public: Date& operator + (const Date& d); //note: operator += not defined }; Date d1, d2; d1 = d1 + d2; //fine; uses overloaded + and default assignment operator d1 += d2; //compile time error: 'no user defined operator += for class Date' Theoretically, the compiler could synthesize a compound operator += by combing the assignment operator and the overloaded + operator so that the expression d1 += d2; is automatically expanded into d1 = d1+d2; However, this is undesirable because the automatic expansion might be less efficient than a user-defined version of the operator An automated version creates a temporary object, whereas a user-defined version can avoid it Moreover, it is not difficult to think of situations in which a class has an overloaded operator +, but does not have operator += intentionally Returning Objects by Value For the sake of efficiency, large objects are usually passed to or returned from a function by reference or by their address There are, however, a few circumstances in which the best choice is still to return an object by value Operator + is an example of this situation It has to return a result object, but it cannot modify any of its operands The seemingly natural choice is to allocate the result object on the free store and return its address Nevertheless, this is not such a good idea Dynamic memory allocation is significantly slower than local storage It also might fail and throw an exception, which then has to be caught and handled Even worse, this solution is error prone because it is unclear who is responsible for deleting this object the creator or the user? Another solution is to use a static object and return it by reference For example class Year { private: int year; public: Year(int y = 0) : year(y) {} Year& operator + (const Year& other) const; //returns a reference to //a local static Year int getYear() const; void setYear(int y); }; Year& Year::operator + (const Year& other) const { file:///D|/Cool Stuff/old/ftp/1/1/ch03/ch03.htm (10 von 15) [12.05.2000 14:45:47] ANSI/ISO C++ Professional Programmer's Handbook - Chapter - Operator Overloading static Year result; result = Year(this->getYear() + other.getYear() ); return result; } Static objects solve the ownership problem, but they are still problematic: On each invocation of the overloaded operator, the same instance of the static object is being modified and returned to the caller The same object can be returned by reference to several more users, who not know that they are holding a shared instance that has just been modified behind their back Finally, the safest and most efficient solution is still to return the result object by value: class Year { private: int year; public: Year(int y = 0) : year(y) {} Year operator + (const Year& other) const; //return Year object by value int getYear() const; void setYear(int y); }; Year Year::operator + (const Year& other) const { return Year(this->getYear() + other.getYear() ); } Multiple Overloading Overloaded operators obey the rules of function overloading Therefore, it is possible to overload an operator more than once When is it useful? Consider the following Month class and its associated operator ==: class Month { private: int m; public: Month(int m = 0); }; bool operator == (const Month& m1, const Month &m2); It is possible to use the overloaded operator == to compare a plain int value and a Month object due to the implicit conversion of int to Month For example void f() { int n = 7; Month June(6); bool same = (June == n); //calls bool operator == (const Month& m1, const Month &m2); } file:///D|/Cool Stuff/old/ftp/1/1/ch03/ch03.htm (11 von 15) [12.05.2000 14:45:47] ANSI/ISO C++ Professional Programmer's Handbook - Chapter - Operator Overloading This works fine, but it i's inefficient: The argument n is first converted to a temporary Month object, which is then compared with the object June You can avoid the unnecessary construction of a temporary object by defining additional overloaded versions of operator ==: bool operator == (int m, const Month& month); bool operator == (const Month& month, int m); Consequently, the expression June == n will now invoke the following overloaded operator: bool operator == (const Month& month, int m); This overloaded version does not create a temporary object, so it's more efficient The same performance considerations led the C++ Standardization committee to define three distinct versions of operator == for std::string (see Chapter 10, ""STL and Generic Programming"") and other classes of the Standard Library.' Overloading Operators for Other User-Defined types You can overload an operator for enum types as well For example, it may be useful to overload operators such as ++ and so that they can iterate through the enumerator values of a given enum type You can it like this: #include using namespace std; enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; Days& operator++(Days& d, int) // postfix ++ { if (d == Sunday) return d = Monday; //rollover int temp = d; //convert to an int return d = static_cast (++temp); } int main() { Days day = Monday; for (;;) //display days as integers { cout

Ngày đăng: 05/08/2014, 10:20