Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Билеты по ООП.doc
Скачиваний:
4
Добавлен:
14.04.2019
Размер:
596.48 Кб
Скачать

26. Ссылки

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

Параметры-ссылки

По умолчанию С++ передаёт аргументы в функцию по значению.

В С++ можно создавать передаваемые по ссылке параметры. Для этого при объявлении функции перед параметром ставится знак амперсанта &.

Пример

void f(int &f)

{ f = rand( ); }

Инструкция

f = rand( );

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

int val;

f(val);

printf(“%d”, val);

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

На применение переменных ссылочного типа имеется ряд ограничений:

  1. Нельзя взять ссылку от переменной ссылочного типа, иными словами, нельзя взять её адрес.

  2. Нельзя создать массив ссылок.

  3. Нельзя создать указатель на ссылку.

  4. Ссылки на битовые поля не допускаются.

27. Наследование и спецификаторы доступа

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

Наследование является одной из главных особенностей объектно-ориентированного программирования. В С++ наследование поддерживается за счет того, что одному классу разрешается при своем объявлении включать в себя другой класс. Наследование позволяет построить иерархию классов от более общего к более частным. Этот процесс включает в себя определение базового класса, определяющего общие качества всех объектов, которые будут выведены затем из базового класса. Базовый класс представляет собой наиболее общее описание. Выведенные из базового класса классы обычно называют производными классами.

Пример

#include <iostream>

using namespace std;

class road_vehicle {

int wheels;

int passengers;

public:

void set_wheels(int num);

int get_wheels( );

void set_pass(int num);

int get_pass( );

};

class truck: public road_vehicle {

int cargo;

public:

void set_cargo(int size);

int get_cargo( );

void show( );

};

enum type {car, van, wagon};

class automobile: public road_vehicle {

enum type car_type;

public:

void set_type(enum type t);

enum type get_type( );

void show( );

};

void road_vehicle::set_wheels(int num)

{

wheels = num;

}

int road_vehicle::get_wheels( )

{

return wheels;

}

void road_vehicle::set_pass(int num)

{

passengers = num;

}

int road_vehicle::get_pass( )

{

return passengers;

}

void truck::set_cargo(int num)

{

cargo = num;

}

int truck::get_cargo( )

{

return cargo;

}

void truck::show( )

{

cout << “Wheels: “ << get_wheels( ) << “\n”;

cout << “Passengers: “ << get_pass( ) << “\n”;

cout << “Cargo capacity in cubic feet:“ << cargo << “\n”;

}

void automobile::set_type(enum type t)

{

car_type = t;

}

enum type automobile::get_type( )

{

return car_type;

}

void automobile::show( )

{

cout << “Wheels: “ << get_wheels( ) << “\n”;

cout << “Passengers: “ << get_pass( ) << “\n”;

cout << “Type: “;

switch(get_type( )) {

case van: cout << “Van\n”;

break;

case car: cout << “Car\n”;

break;

case wagon: cout << “Wagon\n”;

}

}

Общая форма записи наследования имеет следующий вид

class имя_нового_класса: спецификатор_доступа наследуемый_класс{

// тело нового класса

};

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

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

Спецификаторы доступа

В С++ члены класса классифицируются в соответствии с правами доступа на следующие три категории: публичные (public), частные (private) и защищённые (protected). Любая функция программы имеет доступ к публичным членам. Доступ к частному члену имеют только функции-члены класса или функции-друзья класса. Защищённые члены аналогичны частным членам. Разница между ними проявляется только при наследовании классов.

Частные члены базового класса не доступны внутри производного класса.

Например

class X {

int i;

int j;

public:

void get_ij();

void put_ij();

};

class Y: public X {

int k;

public:

int get_k();

void make_k();

};

Класс Y наследует и имеет доступ к публичным функциям get_ij() и put_ij() класса Х, но не имеет доступа к i и j, поскольку они являются частными членами Х.

Для того, чтобы оставить член частным и разрешить использовать его производным классам используется ключевое слово – protected.

Пример

class X {

protected:

int i;

int j;

public:

void get_ij();

void put_ij();

};

class Y: public X {

int k;

public:

int get_k();

void make_k();

};

Здесь класс Y имеет доступ к i и j, и в то же время они остаются недоступными для другой части программы.

Спецификатор доступа при наследовании базового класса

От того, с каким спецификатором доступа объявляется наследование базового класса, зависит статус доступа к членам производного класса. Общая форма наследования классов имеет следующий вид:

class имя_класса: доступ имя_класса { ... };

Здесь доступ определяет, каким способом наследуется базовый класс. Спецификатор доступ может принимать три значения – private, public, protected. В случае если спецификатор доступа опущен, то по умолчанию подразумевается на его месте спецификатор public. Если спецификатор доступ принимает значение public, то все публичные и защищённые члены базового класса становятся соответственно публичными и защищёнными членами производного класса. Если доступ private, то все публичные и защищённые члены базового класса становятся частными членами производного класса. Если спецификатор доступа protected, то все публичные и защищённые члены базового класса становятся защищёнными членами производного класса. Рассмотрим пример:

#include <iostream>

using namespace std;

class X {

protected:

int i;

int j;

public:

void get_ij(){

cout << "Enter two numbers ";

cin >> i >> j;

}

void put_ij(){ cout << i << " " << j << "\n";}

};

// В классе Y, i и j класса X становятся защищёнными членами

class Y: public X {

int k;

public:

int get_k(){ return k;}

void make_k(){ k=i*j;}

};

// Класс Z имеет доступ к i и j класса X, но не к

// k класса Y, поскольку он является частным

class Z: public Y {

public:

void f();

};

// i и j доступны отсюда

void Z::f()

{

i=2;

j=3;

}

int main()

{

Y var;

Z var2;

var.get_ij();

var.put_ij();

var.make_k();

cout << var.get_k();

cout << "\n";

var2.f();

var2.put_ij();

return 0;

}

Поскольку класс Y наследует класс X со спецификатором доступа public, то защищённые элементы класса X становятся защищёнными элементами класса Y. Это означает, что они могут далее наследоваться классом Z, и эта программа будет откомпилирована и выполнена корректно. Однако, если изменить статус X при объявлении Y на private, то класс Z не имеет доступа к i, j и функциям get_ij() и put_ij(), поскольку они стали частными членами Y.