Инструменты пользователя

Инструменты сайта


перегрузка_операторов

Назад

Перегрузка операторов

В С++ есть возможность распространения действия стандартных операций на операнды абстрактных типов данных.
Для того чтобы использовать метод перезагрузки операторов используется ключевое слово operator знак.

a @ b -> a.operator(b)
    	      -> operator @ (a, b)
------------------------------
@ @ a -> a.operator
            -> operator @ (a)
@ a @ -> a.operator (int)
            -> operator @ (a, int)

* символ @ - оператор

Пример сложение 2 объектов и передача значения 3 объекту

Первая версия сложение без перегрузки операторов.

#include <iostream>
#include <windows.h>
using namespace std;
class A
{
public:
	A(int a,int b)
	{
		ma=a;
		mb=b;
	}
	int GetA ()
	{
		return ma;
	}
	int GetB ()
	{
		return mb;
	}
	void Show()
	{
		cout<<ma<<" "<<mb<<endl;
	}
private:
	int ma;
	int mb;
};
void main ()
{
	A a(15,10);
	a.Show();
	A b(20,20);
	b.Show();
	A c(a.GetA()+b.GetB(),b.GetA()+a.GetB());
	c.Show();
}

Вторая версия сложение с перегрузкой операторов.

#include <iostream>
using namespace std;
class Var
{
private:
	int integer;
public:
	Var (int a=0)
	{
		integer=a;
	}
	void Show ()
	{
		cout<<integer<<endl;;
	}
	const Var & operator + (Var & obj)
	{
		return obj.integer+integer;
	}
	const Var & operator + (int temp)
	{
		return integer+temp;
	}
	friend Var operator + (const Var & temp1,const Var & temp2)
	{
		return temp1.integer+temp2.integer;
	}
 
};
void main () 
{
	Var a=10;
	Var b=10;
	Var c=a+b;
	c.Show();
	c=a+20;
	c.Show();
	c=30+a;
	c.Show();
	c=40+10;
	c.Show();
 
 
}

Дополнительно

#include <iostream>
using namespace std;
class CTest
{
private:
	char *str;
public:
	CTest (char *str)
	{
		this->str=new char [strlen(str)+1];
		strcpy(this->str,str);
	}
	const CTest & operator + (const char *tmp)
	{
		char *temp=new char [strlen(tmp)+strlen(str)+1];
		strcpy(temp,str);
		strcat(temp,tmp);
		delete []str;
		str=new char [strlen(temp)+1];
		strcpy(str,temp);
		delete []temp;
		return *this;
	}
	const CTest & operator += (const char *tmp)
	{
		char *temp=new char [(strlen(tmp)+strlen(str)+1)];
		strcpy(temp,str);
		strcat(temp,tmp);
		delete []str;
		str=new char [strlen(temp)+1];
		strcpy(str,temp);
		delete []temp;
		return *this;
	}
	const bool  operator == (const char *tmp)
	{
		if (stricmp(str,tmp)==0)
		{
			cout<<"true"<<endl;
			return true;
		}
		else 
		{
			cout<<"false"<<endl;
			return false;
		}
	}
	void Show ()
	{
		cout<<str<<endl;
	}
};
void main ()
{
	CTest A("Hello");
	CTest B=(A+" World");
	B.Show();
	B+=" C++";
	B.Show();
	B=="Hello World C++";
}

Перегрузка оператор присваивания

Оператор присваивания в языке программирования C++ обозначается знаком '='. Как и другие операторы в C++, она может быть перегружена.

Оператор присваивания отличается от конструктора копирования тем, что должен очищать члены-данные цели присваивания (и правильно обрабатывать самоприсваивание), тогда как конструктор копирования присваивает значения неинициализированным членам-данным.

CTest first;           // инициализация конструктором по умолчанию
CTest second = first;  // инициализация конструктором копирования
second = first;         // присваивание операцией присваивания копированием

Этапы создание оператора присваивания:

#include <iostream>
using namespace std;
class CTest
{
private:
	char *str;
	size_t leng; //unsigned int
public:
	CTest ()
	{
		str=new char [strlen("12345")+1];
		strcpy(str,"12345");
		leng=0;
	}
	CTest & operator = (const CTest & obj)
	{
 
		// 1: защита от неправильного самоприсваивания
		if (this == & obj)
		{
			return *this;
		}
 
		// 2: освобождаем "старую" память
		delete []str;
 
		// 3: присваиваем значения в "новой" памяти объекту
		str = new char [strlen(obj.str)+1];
		strcpy(str,obj.str);
		leng=obj.leng;
		return *this;
	}
	~CTest()
	{
		delete []str;
	}
};
 
void main ()
{
	CTest a;
	CTest b;
	a=b;
}

Перегрузка операторов ++ --

В отличие от всех других унарных операций операции ++ и – имеют, кроме префиксной формы еще и постфиксную. Это привело к особенностям при их перегрузке.

Чтобы перегрузить операцию инкремента для получения возможности использования и префиксной, и постфиксной форм, каждая из этих двух перегруженных функций-членов, должна иметь разную сигнатуру, чтобы компилятор имел возможность определить, какая версия ++ имеется в виду в каждом конкретном случае. Префиксный вариант перегружается так же, как любая другая унарная операция.

Префиксная перегрузка

#include <iostream>
using namespace std;
class A
{
public:
	A(int a)
	{
		ma=a;
	}
	void Show()
	{
		cout<<ma<<endl;
	}
	A & operator ++()
	{
		this->ma++;
		return *this;
	}
private:
	int ma;
};
void main ()
{
	A a(10);
	a.Show();
	++a;
	a.Show();
}

Постфиксная перегрузка

#include <iostream>
using namespace std;
class A
{
public:
	A(int a)
	{
		ma=a;
	}
	void Show()
	{
		cout<<ma<<endl;
	}
	A operator ++(int)
	{
		A temp(*this);
		this->ma++;
		return temp;//передали темп со старым значением ma
	}
private:
	int ma;
};
void main ()
{
	A a(10);
	a.Show();
	A c=a++;//10
	c=a++;//11
	c.Show();
 
}

Перегрузка оператора индексации

Является унарным оператором, обычно использующимся для доступа к элементам контейнера

  • В качестве типа индекса может использоваться произвольный тип.

Поскольку доступ к элементам может быть как на чтение, так и на запись, существуют две формы данного оператора.

  • Оператор доступа для чтения является константным и возвращает константу или константную ссылку на элемент контейнера.
  • Оператор доступа для записи является не константным и возвращает ссылку на элемент контейнера.

Программист может перегрузить данный оператор иными способами, однако это может ввести в заблуждение других программистов

Чтение

#include <iostream>
using namespace std;
class A
{
private:
	int m_array[10];
public:
	A()
	{
		for (int i=0;i<10;i++)
		{
			m_array[i]=100+i;
		}
	}
	void Show ()
	{
		for (int i=0;i<10;i++)
		{
			cout<<m_array[i]<<" ";
		}
		cout<<endl;
	}
	int GetElem(int index)
	{
		return m_array[index];
	}
	const int operator [](int index)const
	{
		return m_array[index];
	}
 
};
void main ()
{
	A a[3];
	a[0].Show();
	int b=a[0].GetElem(4);
	cout<<b<<endl;//cout<<a[0].GetElem(4);--вывод по элементам
	cout<<a[0][1]<<endl;//вывод по элементам
}

Запись

#include <iostream>
using namespace std;
class A
{
private:
	int m_array[10];
public:
	A()
	{
		for (int i=0;i<10;i++)
		{
			m_array[i]=100+i;
		}
	}
	void Show ()
	{
		for (int i=0;i<10;i++)
		{
			cout<<m_array[i]<<" ";
		}
		cout<<endl;
	}
	int GetElem(int index)
	{
		return m_array[index];
	}
	int & operator [](int index)
	{
		return m_array[index];
	}
 
};
void main ()
{
	A a[3];
	a[0].Show();
	a[0][0]=111;//записываем в 1  элемент
	a[0].Show();
}

Перегрузка потока

#include <iostream>
using namespace std;
class A
{
private:
	int a;
	int b;
public:
	A(int m)
	{
		a=m;
	}
	void Show ()
	{
		cout<<a<<endl;
	}
	friend ostream & operator << (ostream & str,const A & t)
	{
		return str<<t.a;
	}
	friend istream & operator >> (istream & str,A & t)
	{
		return str >>t.a;
	}
};
void main ()
{
	A a(100);
	a.Show();
	cout<<a<<endl;
	cin>>a;
	cout<<a<<endl;
}

Перегрузка все операторов

#include <iostream>
using namespace std;
class A  
{
private:
	int a;
public:
	A(int a=0)
	{
		this->a=a;
	}
	void Show()
	{
		cout<<a<<endl;;
	}
 
	const A & operator + (A & temp)
	{
		return a+temp.a;
	}
	const A & operator + (int b)
	{
		return a+b;
	}
 
	friend A operator + (const A & a,A & b)
	{
		return a.a+b.a;
	}
 
};
 
void main () 
{
	A a(10);
	A b(20);
	A c=a+b;
	c.Show();
	c=a+30;
	c.Show();
	c=40+a;
	c.Show();
	c=40+40;
	c.Show();
 
}