Перегрузка операций и дружественные функции




Листинг 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;

}

 

 

Результат:

 

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 ей не передается.

· Дружественная функция может быть обычной функцией или методом другого ранее определенного класса. На нее не распространяется действие спецификаторов доступа, место размещения ее объявления в классе безразлично.

· Одна функция может быть дружественной сразу нескольким классами


Наследование

Наследование (inheritance) — это процесс, в ходе которого один объект может приобретать свойства другого. Он имеет большое значение, поскольку поддерживает концепцию классификации (classification).

Все знания организованы по принципу иерархической классификации. Например, антоновка (сорт яблока) относится к классу “яблоки”, который в свою очередь является частью класса “фрукты”, входящего в класс “пища".

Если бы классификации не существовало, мы не смогли бы точно описать свойства объектов. Однако при этом необходимо указывать только уникальные свойства объекта, позволяющие выделить его среди других объектов данного класса. Именно этот принцип лежит в основе механизма наследования, дающего возможность считать конкретный объект специфическим экземпляром более общей разновидности.

Класс, лежащий в основе иерархии, называется базовым (base class), а класс, наследующий свойства базового класса, — производным (derived class). Производные классы, в свою очередь, могут быть базовыми по отношению к другим классам.

Классы, находящиеся ближе к началу иерархии, объединяют в себе наиболее общие черты для всех нижележащих классов. По мере продвижения вниз по иерархии классы приобретают все больше конкретных черт.

Синтаксис:

class имя: [private | protected | public] базовый_класс

{ тело класса };

[private | protected | public] - ключи доступа.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-07-02 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: