/* Предефиниране на бинарна операция -
с аргументи от клас Time и стойност от тип long */
long operator-(Time a, Time b)
/* ЦЕЛ: пресмята броя на секундите между
два момента от време
ПОЛУЧАВА: a, b - два
момента от време
ВРЪЩА: броя на секундите
между a и b
*/
{ return
a.seconds_from(b); }
/* Предефиниране на бинарна операция +
с аргументи от клас Time и тип long и стойност от
клас Time */
Time operator+(Time a, long sec)
/* ЦЕЛ: пресмята момент от време,
отдалечен на зададен брой секунди
ПОЛУЧАВА: a - момент от
време
ВРЪЩА: момент от време, отдалечен на зададения брой
секунди
*/
{ Time r = a;
r.add_seconds(sec);
return r; }
/* Предефиниране на бинарна операция ==
с аргументи от клас Time и стойност от тип bool */
bool operator==(Time a, Time b)
/* ЦЕЛ: сравнява два
момента от време
ПОЛУЧАВА: a, b - два
момента от време
ВРЪЩА: true ако те са равни
и false ако не са равни
*/
{ return a.seconds_from(b) ==
0; }
/* Предефиниране на бинарна операция !=
с аргументи от клас Time и стойност от тип bool */
bool operator!=(Time a, Time b)
/* ЦЕЛ: сравнява два
момента от време
ПОЛУЧАВА: a, b - два
момента от време
ВРЪЩА: true - ако те не са
равни
*/
{ return a.seconds_from(b) !=
0; }
/* Предефиниране на бинарна операция
<< с аргументи от клас ostream и клас Time и стойност
от тип ostream */
ostream &operator<<(ostream
&out, const Time &a)
/* ЦЕЛ: отпечатва обект от тип Time
ПОЛУЧАВА: out - изходен
поток, a - момент
от време
ВРЪЩА: входния параметър
out
*/
{ out << a.get_hours()
<< ":";
if (a.get_minutes() <
10) out << "0";
out <<
a.get_minutes() << ":";
if (a.get_seconds() <
10) out << "0";
out <<
a.get_seconds();
return
out; }
/* Предефиниране на унарна операция -
префиксна форма на ++ с аргумент от клас Time и стойност от клас Time */
Time operator++(Time &a)
/* ЦЕЛ: добавя към момент от време 1
секунда
ПОЛУЧАВА: a - момент от
време
ВРЪЩА: новият момент от
време и променя a
*/
{ a = a + 1; return a; }
/* Предефиниране на унарна операция -
постфиксна форма на ++ с аргумент от клас Time и стойност от клас Time */
Time operator++(Time &a, int
dummy)
/* ЦЕЛ: добавя към момент от време 1
минута
ПОЛУЧАВА: a - момент от
време
ВРЪЩА: непромененият момент
от време и променя a
*/
{ Time b = a;
a = a + 60; return b;
}
int main()
{ Time now;
cout << "Now it is
" << now << "\n";
Time later = now + 1000;
cout << "A
thousand seconds later it is " << later << "\n";
Time now2;
if (now == now2)
cout
<< "It still is " << now2 << "\n";
if (now != now2)
cout
<< "It is already " << now2 << "\n";
cout << "Another "
<< later - now2 << " seconds until "
<<
later << "\n";
now = Time();
cout << "Now it is
" << now << "\n";
cout << "One
second later " << (++now) << "\n";
cout << "The same
time " << (now++);
cout << " and 60
seconds later " << now << "\n";
return 0;
}
Now it is 11:42:51
A thousand seconds later it is 11:59:31 It still is 11:42:51 Another 1000 seconds until 11:59:31 Now it is 11:42:51 One second later 11:42:52 The same time 11:42:52 and 60 seconds later 11:43:52 |
// overload1.cpp
#include <iostream>
#include <iomanip>
using namespace std;
#include "ccc_time.h"
class Time_new : public Time {
public:
int operator-(Time_new b) const;
Time_new operator+(int sec) const;
bool operator==(Time_new b) const;
bool operator!=(Time_new b) const;
Time_new operator++(); // prefix
Time_new operator++(int dummy); // postfix
friend ostream& operator<<(ostream& out, Time_new a);
};
/**
Compute the number of seconds between two points in time.
@param b another point in time
@return the number of seconds that a is away from b
*/
int Time_new::operator-(Time_new b) const
{ return this->seconds_from(b);
}
/**
Compute a point in time that is some number of seconds away.
@param sec the seconds to add
@return a point in time that is sec seconds away from a
*/
Time_new Time_new::operator+(int sec) const
{ Time_new r = *this;
r.add_seconds(sec);
return r;
}
/**
Compare two points in time
@param b another point in time
@return true if they are the same
*/
bool Time_new::operator==(Time_new b) const
{ return this->seconds_from(b) == 0;
}
/**
Compare two points in time.
@param b another point in time
@return true if they are the different
*/
bool Time_new::operator!=(Time_new b) const
{ return !(*this == b);
}
/**
Prefix increment by 1 second.
@return the new value
*/
Time_new Time_new::operator++() // prefix
{ *this = *this + 1;
return *this;
}
/**
Postfix increment by 1 second.
@return the old value
*/
Time_new Time_new::operator++(int dummy) // postfix
{ Time_new t = *this;
*this = *this + 1;
return t;
}
/**
Print a Time object
@param out an output stream
@param a a point in time
@return out
*/
ostream& operator<<(ostream& out, Time_new a)
{ out << a.get_hours() << ":"
<< setw(2) << setfill('0')
<< a.get_minutes() << ":"
<< setw(2) << a.get_seconds() << setfill(' ');
return out;
}
int main()
{ Time_new now;
cout << "now: " << now << endl;
Time_new later = now + 1000;
cout << "later: " << later << endl;
Time_new now2;
if (now == now2)
cout << "now == now2: " << now2 << endl;
if (now != now2)
cout << "now != now2 " << now2 << endl;
cout << "now++: " << now++
<< " ++now2: " << ++now2 << endl;
cout << "now: " << now << " now2: " << now2 << endl;
cout << "later - now2: " << later - now2 << endl;
return 0;
}
Сега можем да заменим функциите в класовете за реализация на свързан
списък (list2.cpp),
които заместваха операциите от STL-реализацията с
предефинирани операции:bool operator!=(Iterator a, Iterator
b); /* външна за класа функция
*/
bool Iterator::operator!=(Iterator
b); /* член-функция
*/
string Iterator::operator*() const
{ assert(position != NULL);
return
position->data; }
void Iterator::operator++(int dummy)
{ assert(position != NULL);
position =
position->next; }
void Iterator::operator--(int dummy)
{ if (position == NULL)
position = last;
else
position
= position->previous;
assert(position !=
NULL); }
bool Iterator::operator!=(Iterator
b) const
{ return position !=
b.position; }
bool Iterator::operator==(Iterator
b) const
{ return position ==
b.position;
Управление
на паметта
Ще разгледаме примера от Указатели за
използване на указател в клас - department.cpp.
// department0.cppПроменяме конструктора на класа, като там конструираме обект - член-данна на класа.
#include <string> #include <iostream> using namespace std; #include "ccc_empl.h" /**
A department in an organization. */ class Department { public: Department(string n); void set_receptionist(Employee* e); void print() const; private: string name; Employee* receptionist; }; /** Constructs a department with a given name. @param n the department name */ Department::Department(string n) { name = n; receptionist = NULL; } /** Sets the receptionist for this department. @param e the receptionist */ void Department::set_receptionist(Employee* e) { receptionist = e; } /** Prints a description of this department. */ void Department::print() const { cout << "Name: " << name << "\n" << "Receptionist: "; if (receptionist == NULL) cout << "None"; else cout << receptionist->get_name() << " " << receptionist->get_salary(); cout << "\n"; } int main() { Department shipping("Shipping"); Department qc("Quality Control"); Employee* harry = new Employee("Hacker, Harry", 45000); shipping.receptionist(harry); Employee* tina = new Employee("Tester, Tina", 50000); qc.set_receptionist(tina); tina->set_salary(55000); shipping.print(); qc.print();
delete harry;
delete tina;
return 0; }
class Department {
...
private: string name;
Employee* receptionist;
};
Department::Department(string n, Employee e)
{
name = n; receptionist = new Employee(e.get_name(), e.get_salary());
}
/* second constructor */
Department::Department(string n)
{
name = n;
receptionist = NULL;
}
** Деструктор
Деструктор е специална член-функция, която се извиква автоматично
когато обектът излезе от обхват.
Деструкторът на класа Department трябва да унищожи
създадения от конструктора обект:
** Предефиниране на операция за присвояване
Нека имаме следните дефиниции:
Department qc("Quality Control", Employee("Tester, Tina", 50000));
Department dept("Shipping", Employee("Hacker, Harry", 35000));
и след това приложим операция присвояване (почленно копиране):
dept = qc;
1. Това присвоявано води до загуба на памет (memory leak) - имаме
недостъпен обект (от тип Employee)!
2. Когато един от обектите (qc или dept) излезе
от обхват (и изтрие обекта), получаваме висящ указател (dangling
pointer)!
Затова трябва да предефинираме операция присвояване за обекти от класа Employee
Department& Department::operator=(const Department& b)
{ if (this != &b)
{ name = b.name;
delete receptionist;
if (b.receptionist == NULL) receptionist == NULL;
else
receptionist = new Employee(b.receptionist->get_name(),
b.receptionist->get_salary());
}
return *this;
}
Променяме данните, които не са указатели (в случая name)
от обект b в *this, изтриваме указателя receptionist
от *this и създаваме нов обект от тип Employee
за *this, копие на обекта *receptionist
от b.
Функцията за предефиниране трябва да е член-функция (защо)?
** Конструктор за копиране
Предназначението на операция присвояване е да промени съшествуващ
обект, като го направи същия, както друг обект и не е подходяща за
конструиране на нов обект.
Например в оператора за дефиниране на обект:
Department dept = qc; // not assignment operator!
не може да се използва (и не е!) операция присвояване.
Правилното конструиране на обект, копие на друг обект е:
Department dept(qc);
т.е. като се извика конструктор за копиране.
За всеки клас в езика С++ има такъв конструктор, но той действа с
почленно копиране и възникава същия проблем, както при операция
присвояване.
Решението е да се напише конструктор за копиране:
Department::Department(const Department& b)
{ name = b.name;
if (b.receptionist == NULL) receptionist = NULL;
else
receptionist = new Employee(b.receptionist->get_name(),
b.receptionist->get_salary());
}
Конструктор за копиране се вика и когато се предава
параметър-стойност на функция, напр.
void print(Department d)
{ ... }
Department dep("Administration")
...
print(dep);
....
Пример:
// department.cppКогато използваме указатели (и динамична памет) в данните на клас, винаги трябва да дефинираме "големите три":
001: #include <string> 002: #include <iostream> 004: using namespace std; 005: 006: #include "ccc_empl.h" 008: /** 009: A department in an organization. 010: */ 011: class Department { 013: public: 014: Department(string n); 015: Department(string n, Employee e); 016: ~Department(); 017: Department& operator=(const Department& b); 018: Department(const Department& b); 019: void print() const; 020: private: 021: string name; 022: Employee* receptionist; 023: }; 024: 025: /** 026: Constructs a department with a given name and no receptionist. 027: @param n the department name 028: */ 029: Department::Department(string n) 030: { name = n; 032: receptionist = NULL; 034: cout << "Constructor: "; 035: print(); 036: } 037: 038: /** 039: Constructs a department with a given name and receptionist. 040: @param n the department name 041: @param e the receptionist 042: */ 043: Department::Department(string n, Employee e) 044: { name = n; 046: receptionist = new Employee(e.get_name(), e.get_salary()); 048: cout << "Constructor: "; 049: print(); 050: } 051: 052: /** 053: Deletes the Employee object that this Department 054: object manages. 055: */ 056: Department::~Department() 057: { cout << "Destructor: "; 059: print(); 061: delete receptionist;
062: } 063: 064: /** 065: Constructs a Department object as a copy of another 066: Department object. 067: @param b the object to copy 068: */ 069: Department::Department(const Department& b) 070: { cout << "Copy constructor: "; 072: b.print(); 073: 074: name = b.name; 075: if (b.receptionist == NULL) receptionist = NULL; 077: else 078: receptionist = new Employee(b.receptionist->get_name(), 079: b.receptionist->get_salary()); 080: } 081: 082: /** 083: Sets this Department object to a copy of another 084: Department object. 085: @param b the object to copy 086: */ 087: Department& Department::operator=(const Department& b) 088: { cout << "Assignment: "; 090: print(); 091: cout << "= "; 092: b.print(); 093: 094: if (this != & b) 095: { name = b.name; 097: delete receptionist; 098: if (b.receptionist == NULL) receptionist = NULL; 100: else 101: receptionist = new Employee(b.receptionist->get_name(), 102: b.receptionist->get_salary()); 103: } 104: return *this; 105: } 106: 107: /** 108: Prints a description of this department. 109: */ 110: void Department::print() const 111: { cout << "[name=" << name << ",receptionist="; 113: if (receptionist == NULL) cout << "NULL"; 115: else cout << receptionist->get_name(); 117: cout << "]\n"; 118: } 119: 120: int main() 121: { Department shipping("Shipping"); 123: Department qc("Quality Control",
124: Employee("Tester, Tina", 50000)); 125: Department dept(qc);
126: dept = shipping; 127: return 0; 128: }