Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 13.12.2020

Просмотров: 4295

Скачиваний: 28

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Часть II. Язык программирования С++ 

186 

Определение  класса 

PrintBox

  поместим  в  заголовочный  файл 

PrintBox.h, текст которого приведен в листинге 14.6. 

Листинг 14.6. Определение дружественного класса 

#include "IntBox.h" 
#include <iostream> 
using namespace std; 
 
#if !defined PRINT_BOX 
#define PRINT_BOX 
struct PrintBox 

  void print(IntBox& box); 
}; 
#endif 

Реализацию функции 

print

 из класса 

PrintBox

 поместим в исход-

ный файл PrintBox.cpp, текст которого приведен в листинге 14.7. 

Листинг 14.7. Реализация функции дружественного класса 

#include "PrintBox.h" 
void PrintBox::print(IntBox& box) { cout << box.room; } 

В  листинге  14.8  показано,  как  распечатывать  содержимое  кон-
тейнера при помощи функции 

print

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

#include "IntBox.h" 
#include "PrintBox.h" 
#include <iostream> 
using namespace std; 
int main() 

  IntBox box; 
  PrintBox prn; 


background image

Глава 14. Классы 

187 

  box.put(10); 
  prn.print(box);  // печатает 10 
  cout << endl; 
  return 0; 

При использовании друзей класса следует учитывать следующие 
правила: 

 

отношение  дружбы  не  является  симметричным,  т. е.  если  А 
есть друг В, то из этого не следует, что В есть друг А; 

 

отношение  дружбы  не  является  транзитивным,  т. е.  если  А 
друг В и В друг С, то из этого не следует, что А является дру-
гом С; 

 

отношение дружбы не наследуется, т. е. если класс А является 
другом  класса  С  и  предком  класса  В,  то  из  этого  не  следует, 
что класс В является другом класса С. 

14.7. Встроенные функции-члены 

класса 

Если функция-член класса определена прямо в теле класса, то она 
считается 

встроенной

.  В  этом  случае  ключевое  слово 

inline

 

можно  не  писать.  Например,  определим  все  функции  класса 

IntBox

 как встроенные. 

  class IntBox 
  { 
    bool empty; 
    int  room; 
  public: 
    IntBox() { empty = true; } 
    void put(int n) { room = n; empty = false; } 
    int  get() { empty = true; return room; } 
    bool isEmpty() { return empty; } 
  }; 

В  этом  случае  исходный  файл  IntBox.cpp  нужно  исключить  из 
проекта. 


background image

Часть II. Язык программирования С++ 

188 

Если при объявлении функции-члена класса используется ключе-
вое слово 

inline

, то определять функцию можно и вне тела клас-

са,  при  этом  слово 

inline

  можно  опустить.  Так  как  встроенные 

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

14.8. Функции-члены класса 
с квалификаторами 

const

 и 

volatile

 

Функции-члены  класса  могут  иметь  квалификатор 

const

,  или 

volatile

,  или  два  этих  квалификатора  вместе.  Эти  квалификато-

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

const

.  Для  неконстантного  объекта  класса  могут  быть  вызваны 

функции  как  с  квалификатором 

const

,  так  и  без  него.  Поэтому 

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

const

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

IntBox

  следую-

щим образом: 

  class IntBox 
  { 
    bool empty; 
    int  room; 
  public: 
    IntBox();       // инициализация пустого контейнера 
    IntBox(int n);  // инициализация полного контейнера 


background image

Глава 14. Классы 

189 

    void put(int n); 
    int  get(); 
    int  get() const; 
    bool isEmpty() const; 
  }; 

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

get

  с  квалификатором 

const

,  который  позволит  просматри-

вать  содержимое  константного  контейнера.  Реализация  этих  но-
вых функций выглядит следующим образом: 

  IntBox::IntBox(int n) { empty = false; room = n; } 
  int  IntBox::get() const { return room; } 

А  реализация  функции 

isEmpty()

  не  изменится.  Теперь  можно 

определять константные контейнеры для хранения целых чисел и 
определять  их  содержимое.  Ниже  приведен  пример  использова-
ния константного контейнера. 

  int main() 
  { 
    const IntBox box(10); 
    int n; 
 
    if (!box.isEmpty()) 
      n = box.get(); 
    cout << n << endl;  // печатает 10 
    return 0; 
  } 

Для  объекта  класса,  объявленного  со  спецификатором  доступа 

volatile

,  могут  быть  вызваны  только  те  функции-члены  класса, 

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

volatile

Для  объекта  класса,  объявленного  без  квалификатора 

volatile

могут быть вызваны функции как с квалификатором 

volatile

, так 

и  без  него.  Функцию-член  класса  с  квалификатором 

volatile

 

можно  перегружать  функцией-членом  класса  с  тем  же  списком 
параметров, но без этого квалификатора. 


background image

Часть II. Язык программирования С++ 

190 

Если  в  классе  перегружены  функции-члены  с  квалификаторами 

const

 и 

volatile

, то при вызове такой функции для объекта клас-

са, объявленного без квалификаторов 

const

 и 

volatile

, компиля-

тор выдаст ошибку неоднозначного выбора функции. 

14.9. Данные-члены класса 
с квалификатором 

mutable

 

Чтобы  разрешить  модификацию  члена  класса,  принадлежащего 
константному  объекту,  этот  член  класса  должен  быть  объявлен  
с  квалификатором 

mutable

.  Пример  использования  этого  квали-

фикатора приведен в листинге 14.9. 

Листинг 14.9. Использование квалификатора 

mutable

 

#include <iostream> 
using namespace std; 
class counter 

  mutable int n;  // счетчик обращений 
public: 
  counter() { n = 0; }; 
  int count() const { return ++n; } 
}; 
int main() 

  const counter n; 
  cout << n.count() << endl;  // печатает 1 
 
  return 0; 

14.10. Статические члены класса 

Статические члены класса имеют класс памяти 

static

 и являются 

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


Смотрите также файлы