Перегрузка операций и дружественные функции
Листинг 4: Пример класса стек с перезагрузкой операций
#pragma once
#include <iostream>
namespace stk{
//тип стека
typedef int DType;
class Stack{
DType *stck;
int top;
int size;
public:
//Конструктор
Stack(int s);
Stack(const Stack &st);
~Stack();
// операции модификации стека
void push(const DType &item);
DType pop();
void clear();
// доступ к стеку
DType peek (void) const;
int get_size() const { return size;}
// методы проверки стека
bool isEmpty() const;
bool isFull() const; // реализация массива
Stack operator=(const Stack &st);
friend std::istream &operator>>(std::istream &is, Stack &st);
friend std::ostream &operator<<(std::ostream &os, Stack &st);
friend void operator<<( Stack &st, DType obj);
friend void operator>>(Stack &st, DType &obj);
};
}
Пример реализации:
#include "stack.h"
namespace stk{
//Конструктор
Stack::Stack(int s)
{
top = -1;
stck = new DType[size];
size =s;
}
Stack::Stack(const Stack &st)
{
top = st.top;
size = st.size;
stck = new DType[size];
for(int i=0; i<size; i++)
stck[i] = st.stck[i];
}
Stack::~Stack()
{
delete [] stck;
}
void Stack::push(const DType &item)
{
if (top == size-1){
std::cerr << "Стек полон.\n";
return;
}
stck[++top] = item;
}
DType Stack::pop()
{
if (top == -1){
std::cerr << "Стек пуст.\n";
return 0;
}
return stck[top--];
}
void Stack::clear(void)
{
top = -1;
}
DType Stack::peek() const
{
if (top == -1)
{
std::cerr << "Стэк пуст!\n";
exit(1);
}
return stck[top];
}
bool Stack::isEmpty() const
{
return top == -1;
}
bool Stack::isFull() const
{
return top == size-1;
}
std::istream &operator>>(std::istream &is, Stack &st)
{
if (st.top == st.size-1){
std::cerr << "Стек полон.\n";
return is;
}
is >> st.stck[++st.top];
return is;
}
std::ostream &operator<<(std::ostream &os, Stack &st)
{
if (st.top == -1){
std::cerr << "Стек пуст.\n";
return os;
}
os << st.stck[st.top--];
return os;
}
void operator<<( Stack &st, DType obj)
{
if (st.top == st.size-1){
std::cerr << "Стек полон.\n";
return;
}
st.stck[++st.top] = obj;
}
void operator>>(Stack &st, DType &obj)
{
if (st.top == -1){
std::cerr << "Стек пуст.\n";
return;
}
obj = st.stck[st.top--];
}
Stack Stack::operator=(const Stack &st)
{
delete [] stck;
top = st.top;
size = st.size;
stck = new DType[size];
for(int i=0; i<size; i++)
stck[i] = st.stck[i];
return *this;
}
}
Пример использования:
#include <iostream>
#include "stack_v2.h"
using namespace std;
int main(int argc, char *argv[])
{
system("chcp 65001");
stk::Stack st(5);
for (int i=0; i< st.get_size(); i++){
st << i;
}
stk::Stack st2 = st;
cout << st2 << endl;
st2 = st;
int temp;
for (int i=0; i< st.get_size(); i++){
cout << "st: " << st << endl;
st2 >> temp;
cout << "st2: "<< temp << endl;
}
return 0;
}
Результат:
4
st: 4
st2: 4
st: 3
st2: 3
st: 2
st2: 2
st: 1
st2: 1
st: 0
st2: 0
Перегрузка операций
C++ позволяет переопределить действие большинства операций так, чтобы при использовании с объектами конкретного класса они выполняли заданные функции. Эта дает возможность использовать собственные типы данных точно так же, как стандартные. Обозначения собственных операций вводить нельзя.
тип operator операция (список параметров) {тело функции }
Нельзя перегружать:
. .* ?: :: # ## sizeof
Правила:
при перегрузке операций сохраняются количество аргументов, приоритеты операций и правила ассоциации (справа налево или слева направо), используемые в стандартных типах данных;
для стандартных типов данных переопределять операции нельзя;
функции-операции не могут иметь аргументов по умолчанию;
функции-операции наследуются (за исключением =*);
функции-операции не могут определяться как static.
Функцию-операцию можно определить тремя способами: она должна быть либо методом класса, либо дружественной функцией класса, либо обычной функцией.
Дружественная функция
Дружественные функции применяются для доступа к скрытым полям класса и представляют собой альтернативу методам.
Метод, как правило, используется для реализации свойств объекта, а в виде дружественных функций оформляются действия, не представляющие свойства класса, но концептуально входящие в его интерфейс и нуждающиеся в доступе к его скрытым полям, например, переопределенные операции вывода объектов.
Правила:
Дружественная функция объявляется внутри класса, к элементам которого ей нужен доступ, с ключевым словом friend. В качестве параметра ей должен передаваться объект или ссылка на объект класса, поскольку указатель this ей не передается.
Дружественная функция может быть обычной функцией или методом другого ранее определенного класса. На нее не распространяется действие спецификаторов доступа, место размещения ее объявления в классе безразлично.
Одна функция может быть дружественной сразу нескольким классами
