Главная Обратная связь

Дисциплины:






ОПЕРАТОРЫ, КОТОРЫЕ Вbl HE МОЖЕТЕ ПЕРЕГРУЗИТЬ



В общем случае ваши программы могут перегрузить почти все операторы С++. В табл. 24 перечислены операторы, которые C++ не позволяет перегружать.

Таблица 24. Операторы C++, которые ваши программы не могут перегрузить.

Оператор   Назначение Пример
. Выбор элемента object.member
.* Указатель на элемент object.*member
:: Разрешение области видимости classname::member
?: Условный оператор сравнения с = (а > b) ? а : b;

 

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

Если все методы какого-либо класса должны иметь доступ к скрытым полям другого, весь класс объявляется дружественным с помощью ключевого слова friend. В приведенном ниже примере класс mistress объявляется дружественным классу hero:

class hero{ ... friend class mistress;}class mistress{ ... void f1(); void f1();}

Функции f1 и f2 являются дружественными по отношению к классу hero (хотя и описаны без ключевого слова friend) и имеют доступ ко всем его полям.

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

Объявление дружественного класса позволяет всем его методам получить доступ ко всем переменным и методам другого класса.

Например:

class A {public: int Fx();}

class B {public:

friend class A;

private:

}

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

Например:

class A {public:

// Класс расположен во внешней

// области видимости

int Fx1();

}

namespace classB {

class B {public:

friend class A;

friend class C;

private:

}

class C { public:

// Класс расположен в том же

// пространстве имен

int Fx2();

}

}

Дружественные классы не наследуются, и их дружественность не является транзитивной.

Например:

class A {int Fx();}

class B {friend class A;}

class C {friend class B;}

// Класс А не является

// дружественным классу C

class D : public B {}

// Класс А не является

// дружественным классу D

 

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

Важнейшим свойством объектно-ориентированного программирования является наследование. Для того, чтобы показать, что класс В наследует класс A (класс B выведен из класса A ), в определении класса B после имени класса ставится двоеточие и затем перечисляются классы, из которых B наследует:



class A

{

public:

A();

~A();

MethodA();

};

class B : public A

{

public:

B();

. . .

};

Термин " наследование " означает, что класс B обладает всеми свойствами класса A, он их унаследовал. У объекта производного класса есть все атрибуты и методы базового класса. Разумеется, новый класс может добавить собственные атрибуты и методы.

B b;

b.MethodA(); // вызов метода базового класса

Часто выведенный класс называют подклассом, а базовый класс – суперклассом. Из одного базового класса можно вывести сколько угодно подклассов. В свою очередь, производный класс может служить базовым для других классов. Изображая отношения наследования, их часто рисуют в виде иерархии или дерева.


Рис. 10.1. Пример иерархии классов.

Иерархия классов может быть сколь угодно глубокой. Если нужно различить, о каком именно классе идет речь, класс C называют непосредственным или прямым базовым классом класса D, а класс A – косвенным базовым классом класса D.

Предположим, что для библиотечной системы, которую мы разрабатываем, необходимо создать классы, описывающие различные книги, журналы и т.п., которые хранятся в библиотеке. Книга, журнал, газета и микрофильм обладают как общими, так и различными свойствами. У книги имеется автор или авторы, название и год издания. У журнала есть название, номер и содержание – список статей. В то же время книги, журналы и т.д. имеют и общие свойства: все это – "единицы хранения" в библиотеке, у них есть инвентарный номер, они могут быть в читальном зале, у читателей или в фонде хранения. Их можно выдать и, соответственно, сдать в библиотеку. Эти общие свойства удобно объединить в одном базовом классе. Введем класс Item, который описывает единицу хранения в библиотеке:

class Item

{

public:

Item();

~Item();

// истина, если единица хранения на руках

 

bool IsTaken() const;

// истина, если этот предмет имеется в библиотеке

 

bool IsAvailable() const;

long GetInvNumber() const; // инвентарный номер

 

void Take(); // операция "взять"

void Return(); // операция "вернуть"

 

private:

// инвентарный номер — целое число

long invNumber;

// хранит состояние объекта - взят на руки

bool taken;

};

Когда мы разрабатываем часть системы, которая имеет дело с процессом выдачи и возврата книг, вполне достаточно того интерфейса, который представляет базовый класс. Например:

// выдать на руки

void

TakeAnItem(Item& i)

{

. . .

if (i.IsAvailable())

i.Take();

}

Конкретные свойства книги будут представлены классом Book.

class Book : public Item

{

public:

String Author(void) const;

String Title(void) const;

String Publisher(void) const;

long YearOfPublishing(void) const;

String Reference(void) const;

 

private:

String author;

String title;

String publisher;

short year;

}; // автор

// название

// издательство

// год выпуска

// полная ссылка

// на книгу

Для журнала класс Magazine предоставляет другие сведения:

class Magazine : public Item

{

public:

String Volume(void) const;

short Number(void) const;

String Title(void) const;

Date DateOfIssue() const;

private:

String volume;

short number;

String title;

Date date;

};

// том

// номер

// название

// дата выпуска

Ключевое слово public перед именем базового класса определяет, что внешний интерфейс базового класса становится внешним интерфейсом порожденного класса. Это наиболее употребляемый тип наследования. Описание защищенного и внутреннего наследования будет рассмотрено чуть позже.

У объекта класса Book имеются методы, непосредственно определенные в классе Book, и методы, определенные в классе Item.

Book b;

long in = b.GetInvNumber();

String t = b.Reference();

Производный класс имеет доступ к методам и атрибутам базового класса, объявленным во внешней и защищенной части базового класса, однако доступ к внутренней части базового класса не разрешен. Предположим, в качестве части полной ссылки на книгу решено использовать инвентарный номер. Метод Reference класса Book будет выглядеть следующим образом:

String

Book::Reference(void) const

{

String result = author + "\n"

+ title + "\n"

+ String(GetInvNumber());

return result;

}

(Предполагается, что у класса String есть конструктор, который преобразует целое число в строку.) Запись:

String result = author + "\n"

+ title + "\n"

+ String(invNumber);

не разрешена, поскольку invNumber – внутренний атрибут класса Item. Однако если бы мы поместили invNumber в защищенную часть класса:

class Item

{

. . .

protected:

long invNumber;

};

то методы классов Book и Magazine могли бы непосредственно использовать этот атрибут.

Назначение защищенной ( protected ) части класса в том и состоит, чтобы, закрыв доступ "извне" к определенным атрибутам и методам, разрешить пользоваться ими производным классам .

Если одно и то же имя атрибута или метода встречается как в базовом классе, так и в производном, то производный класс перекрывает базовый.

class A

{

public:

. . .

int foo();

. . .

};

class B : public A

{

public:

int foo();

void bar();

};

void

B::bar()

{

x = foo();

// вызывается метод foo класса B

}

Однако метод базового класса не исчезает. Просто при поиске имени foo сначала просматриваются атрибуты и методы самого класса. Если бы имя не было найдено, начался бы просмотр имен в базовом классе, затем просмотр внешних имен. В данном случае имя foo существует в самом классе, поэтому оно и используется.

С помощью записи A::foo() можно явно указать, что нас интересует имя, определенное в классе A, и тогда запись:

x = A::foo();

вызовет метод базового класса.

Вообще, запись класс::имя уже многократно нами использовалась. При поиске имени она означает, что имя относится к заданному классу.





sdamzavas.net - 2020 год. Все права принадлежат их авторам! В случае нарушение авторского права, обращайтесь по форме обратной связи...