pragma once Hard / Занятие 3
.docПерегрузка операций
Пример 3.1
Создадим класс MyCls следующего вида:
class MyCls {
int *v;
public:
MyCls(void) {v = new int; *v=0;} //конструктор по умолчанию
MyCls(int x) {v = new int; *v=x;} //конструктор с параметром
MyCls(const MyCls &ob) {v = new int; *v=*(ob.v);} //конструктор копирования
~MyCls(void){delete v;} //деструктор
int get() {return *v;} //метод возвращающий значение
MyCls add(MyCls &); //сложение с указанным классом
};
MyCls MyCls::add(MyCls &a) {
*v = *v + a.get();
return *this;
}
Обратите внимание на указатель this в реализации метода add. Методы в памяти существуют в единственном экземпляре в отличие от полей, которые у каждого объекта свои. Чтобы можно было определить, для какого объекта вызван метод, у метода существует скрытый параметр this, в котором хранится указатель на вызвавший функцию объект. Указатель можно использовать для доступа к элементам объекта, а также для возвращения из метода указателя (return this;) или ссылки (return *this;) на вызвавший объект.
Использование класса демонстрирует следующая программа:
int main() {
MyCls A, B(20), C=B;
cout <<A.get()<<','<<B.get()<<','<< C.get() << endl;
cout <<C.add(B).get()<<endl;
}
Создав соответствующие методы, мы можем реализовать любые операции над объектами. Однако, хотелось бы для наших объектов использовать привычные знаки операций, например, вместо C.add(B) написать выражение C+B. С++ позволяет переопределить действие большинства операций так, чтобы они выполняли необходимые действия при использовании с объектами созданного класса.
Можно перегружать любые операции, существующие в С++, кроме
.* ?: :: # ## sizeof
Перегрузка операций реализуется с помощью методов специального вида (функций-операций) и подчиняется следующим правилам:
-
нельзя создавать новые операции;
-
сохраняются количество аргументов, приоритеты операций, используемые в стандартных типах данных;
-
функции-операции не могут иметь параметров по умолчанию;
-
для стандартных типов данных операции переопределять нельзя.
Функция-операция имеет вид:
тип operator операция (список параметров) { тело функции}
Внутри класса унарная функция-операция является нестатическим методом без параметров, при этом операндом является вызвавший ее объект. Бинарная функция-операция – нестатический метод с параметрами, при этом вызвавший ее объект считается первым операндом.
Операция присваивания для любого объекта выполняется как побитовое копирование. Если у объекта есть динамические поля, необходимо создать свою собственную операцию. Операция-функция в этом случае должна возвращать ссылку на объект, для которого она вызвана, и иметь один параметр – ссылку на присваиваемый обект.
Пример 3.2
class MyCls {
int *v;
public:
MyCls(void) {v = new int; *v=0;} //конструктор по умолчанию
MyCls(int x) {v = new int; *v=x;} //конструктор с параметром
MyCls(const MyCls &ob) {v = new int; *v=*(ob.v);} //конструктор копирования
~MyCls(void){delete v;} //деструктор
int get() {return *v;} //метод возвращающий значение
MyCls add(MyCls &); //сложение с указанным классом
MyCls max(MyCls &);
//перегрузка операторов
MyCls operator +( MyCls &); //ob1+ob2
MyCls operator +(int); //ob+целое число
friend MyCls operator +(int, MyCls &);//целое число+ob
bool operator ==( MyCls &); //ob1==ob2
bool operator ==(int); //ob==целое число
friend bool operator ==(int , MyCls &);//целое число==ob
MyCls operator = ( MyCls &); //присваивание
MyCls operator - ();
};
MyCls MyCls::add(MyCls &a){
*v = *v + a.get();
return *this;
}
MyCls MyCls::max(MyCls &a){
if (*v > a.get()) return *this;
return a;
}
MyCls MyCls::operator +( MyCls &ob){ //ob1+ob2
MyCls new_ob;
*(new_ob.v) = *(this->v) + ob.get();
return new_ob;
}
MyCls MyCls::operator +(int x){ //ob+целое число
MyCls new_ob;
*(new_ob.v) = *v + x;
return new_ob;
}
MyCls operator +(int x, MyCls &ob){ //целое число + ob
MyCls new_ob;
*(new_ob.v) = x + ob.get();
return new_ob;
}
bool MyCls::operator ==( MyCls &ob){ //ob1==ob2
return (*v == ob.get());
}
bool MyCls::operator ==(int x){ //ob==целое число
return (*v == x);
}
bool operator ==(int x, MyCls &ob){ //целое число == ob
return (x == ob.get());
}
MyCls MyCls::operator = ( MyCls &ob){ //присваивание
if (&ob==this) return *this;
if (v) delete v;
v = new int;
*v = ob.get();
return *this;
}
MyCls MyCls::operator - (){ //одноместный минус
*v = -*v;
return *this;
}
int main() {
MyCls A(10), B(20), D;
D = A + B;
cout << D.get() << endl; //30
D = D + 30;
cout << D.get() << endl; //60
B = 40 + D;
cout << B.get() << endl; //100
cout << (A == B) << endl; //0
cout << (A == 10) << endl; //1
cout << (100 == B) << endl; //1
A=-B+A;
cout << A.get() << endl; //
return 0;
}
Дружественные функции, не являясь элементами класса, имеют доступ к его закрытым и защищенным элементам. Для того, чтобы объявить функцию дружественной некоторому классу, нужно в этот класс включить ее прототип, перед которым поставить ключевое слово friend.
Дружественная классу функция может быть членом другого класса, или не принадлежать ни к какому классу.
Доступ дружественной функции к закрытым элементам класса можно осуществить только через объект, который объявлен внутри функции или передан ей.