Главная Случайная страница


Полезное:

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


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Дружественные функции





В языке C++ одна и та же функция не может быть членом двух разных классов. Однако, в некоторых ситуациях необходимо иметь доступ из одной функции к локальным (т.е. из части private) компонентам разных классов.

Пример.

Заданы два объекта, описывающие работников различных предприятий:

class Worker {...};

class Engineer {...};

Пусть некоторая функция equal_salary должна сравнивать зарплаты этих работников и сообщать наибольшую из них, то есть функция должна иметь доступ к локальным членам разных объектов. Таким образом, она должна быть член-функцией одновременно двух разных объектов, что невозможно. Для решения указанной проблемы в языке C++ введен спецификатор friend.

Механизм дружественных функций разрешает доступ к локальным членам класса:

- глобальным функциям;

- член-функциям известного на текущий момент класса;

- другому ранее объявленному (или определенному) классу.

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

- не имеет значения, в какой части тела класса (private или public) дружественные функции объявлены,

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

Дружественные глобальные функции.

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

Пример.

Программа сравнивает компоненты объектов разных классов из части private.

#include <iostream.h>

class MyClass2; //Упреждающее описание

class MyClass1

{int a;

friend void fun(MyClass1 &, MyClass2 &);

public:

MyClass1(int B): a(B) {}; //Конструктор

};

class MyClass2

{int a;

friend void fun(MyClass1 &, MyClass2 &);

public:

MyClass2(int B): a(B) {}; //Конструктор

};

void fun(MyClass1 & M1, MyClass2 & M2)

{if (Ml.a == M2.a) //параметры ссылки на объекты

cout<<"\nРавны";//классов, т.к. функция fun не

else cout<<"\nHe равны"; // член этих классов

//и не получает this

}

void main()

{MyClass1 mc1=100, mc2=200;

MyClass2 mc3=100;

fun(mc1, mc3); //Результат: равны

fun(mc2, mc3); //Результат: не равны

}

Дружественные член-функции

Объявить дружественной функцией для класса можно не только глобальную функцию, но и член-функцию другого класса.

Пример.

#include <iostream.h>

class X; // Упреждающие объявление класса

class Y

{int a;

public:

Y(int A): a(A) { };

void display(X *pX); // Член-функция класса Y

};

void Y:: display(X *pX)

{cout<<pX->a<<"\t"<<a<<"\n";

}

void main()

{X MyX(100);

Y MyY(200);

MyY.display(& MyX); // Результат: 100 200

}

Так как display - это член-функция класса Y, она получит указатель this для объектов класса Y, однако, по отношению к классу X - это внешняя функция (т.е. не получает this для этого класса), поэтому получает аргумент-указатель на класс X, чтобы иметь доступ к его членам.

Дружественный класс

Если все член-функции класса X имеют спецификатор friend для класса Y, то класс X можно объявить как дружественный классу Y.

Пример.

class Y

{friend class X;

};

Т.е. все член-функции класса X имеют доступ к локальным членам класса Y.

Основные свойства и правила использования спецификатора friend:

- friend функции не являются членами класса, но получают доступ ко всем его членам независимо от атрибутов этих членов;

- если friend функция - это глобальная функция, то она вызывается без использования «.» и «->»;

- friend функции не получают указателя this того класса, которому они дружественны;

- friend функции не наследуются в производных классах;

- отношение friend не является транзитивным, т.е.

Использование дружественных функции при порождении.

Если класс или функция (внешняя или член другого класса) дружественна базовому, то они:

- имеют доступ ко всем членам этого базового класса;

- не имеют доступа к собственным членам порожденного класса;

- имеют доступ к наследуемым членам порожденного класса.

Если класс или функция объявлена дружественными порожденному классу, то они:

- имеют доступ ко всем собственным членам порожденного класса;

- имеют доступ к членам порожденного класса, наследуемым у базового;

- не имеют доступа к членам базового класса.

 

Перегрузка операций

Любой встроенный в язык C++ тип данных кроме внутреннего представления этих данных определяет неявно еще и набор операций над этими данными.

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

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

Функция operator может быть использована для расширения области применения следующих операторов:

+ - * / % ^ & | ~ = < >

+= /= %= ^= &= |= << >> >>= <<= ==!=

<= >= && || ++ -- ->*, -> [] () new

delete

Нельзя перегружать операции:

..*?*:: sizeof

Конкретный экземпляр операции зависит от типа и числа аргументов. Функция operator используется для расширения области приложения операции # в следующей форме:

тип_возврата operator # (список аргументов),

где # - знак перегружаемой операции из перечисленных.

Правила перегрузки операций.

1. Нельзя использовать для операций новые символы, кроме тех, что определены в языке (например, нельзя использовать $).

2. Нельзя перегружать и определять новые операции для встроенных типов (например, нельзя определить операцию сложения массивов, эту задачу можно решить, определив класс, реализующий понятие массива, и операцию сложения в нем).

3. Нельзя изменить приоритета операции.

4. Нельзя изменить синтаксис операции в выражении (например, если операция определена в языке унарной, то ее нельзя переопределить как бинарную, префиксную операцию нельзя перегрузить как постфиксную).

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

6. При перегрузке унарной операции она не должна иметь аргументов, если является членом класса, и должна иметь один аргумент (ссылку на объект), если является внешней функцией. Если унарная операция перегружается как член-функция, ей передается неявный аргумент - указатель this на текущий объект.

Для любой унарной операции # запись #obj интерпретируется как

- obj.operator #(), если операция является членом класса,

- operator #(obj), если операция является внешней функцией.

Пример.

1) class person 2) class person

{int age; {int age;

… …

public: public:

void operator++() friend void operator++(person&);

{++age;}

}; };

void main() void person:: operator++

(person& ob)

{person jon; {++ob.age;}

++jon; void main()

} {person jon;

++jon;

}

7. При перегрузке бинарной операции она должна иметь один аргумент (ссылку на объект), если является членом класса, и два аргумента (ссылки на объекты), если является внешней функцией. Бинарная операция, перегружаемая как член-функция, получает один неявный аргумент (первый) - указатель this на текущий объект.

Таким образом, для любой бинарной операции # запись objl#obj2 может интерпретироваться:

- как obj1.operator#(obj2), если операция определена как член класса,

- как operator#(obj1, obj2), если операция определена как внешняя функция класса.

Бинарные арифметические операции +, -, *, / должны возвращать объект класса, для которого они используются.

Пример.

1) сlass реrson {...};

class adresbоок

{//содержит в качестве компонентных данных

//множество объектов типа person, представляемых

//как динамический массив, список или дерево}

public:

person &operator[](int); //доступ к i-му объекту

};

person &adresbook:: operator[](int i) {...}

void main()

{

class adresbook persons;

class person record;

record=persons[3];

}

2) сlass реrson {...};

class adresbоок

{//содержит в качестве компонентных данных

//множество объектов типа person, представляемых

//как динамический массив, список или дерево}

public:

friend person& operator[](const adresbook&, int);

//доступ к i-му объекту

};

person& operator[](const adresbook& ob, int i)

{...}

void main()

{

class adresbook persons;

class person record;

record=persons[3];

}

8. Следующие операции

= [] () ->

должны перегружаться только как члены класса.

Date: 2016-05-13; view: 936; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.007 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию