Лекция 4. Введение в C++: уровень доступа к элементам класса, наследование.


1. Уровень доступа к элементам класса


Каждый элемент класса имеет уровень доступа — один из public (открытый), private (закрытый), protected (защищенный).

Этот уровень задается метками “public:”, “private:” и “protected:” в теле описания класса.

По умолчанию (при отсутствии метки) элементы имеют уровень доступа “private”.


Пример 1: Описание класса с различными уровнями доступа к объектам класса:


class A {

friend void func1(int);

int priv; // Закрытый член класса, так как описан в начале класса до задания уровня доступа

void priv_func(int); // Закрытый член класса, так как описан в начале класса до задания уровня доступа

public:

friend void func2(int);

int publ; // Открытый член класса, так как описан после задания уровня доступа “public”

void publ_func(int); // Открытый метод класса, так как описан после задания уровня доступа “public”

protected:

friend void func3(int);

int prot; // Защищенный член класса, так как описан после задания уровня доступа “protected”

int prot_func(int); // Защищенный метод класса, так как описан после задания уровня доступа “protected”

private:

int priv1; // Закрытый член класса, так как описан после задания уровня доступа “private”

int priv2; // Закрытый член класса, так как описан после задания уровня доступа “private”

public:

int publ1; // Открытый член класса, так как описан после задания уровня доступа “public”

};

-------------------------------------------------------------------


Уровень доступа регулирует использование элементов класса в постороннем коде: в коде дружественной функции разрешается обращение к любым элементам класса, в остальном коде вне методов данного класса разрешается обращение только к public элементам (за исключением protected элементов, см. пункт «Наследование»).


Пример 2. Правильное и ошибочное обращения к членам класса из постороннего кода (не из методов класса) (class A см.Пример 1):


void func() {

A a;

x1 = a.priv; // Ошибка: обращение к закрытому члену класса

a.priv_func(a.publ); // Ошибка: обращение к закрытому методу класса

a.publ_func(a.priv); // Ошибка: обращение к закрытому члену класса

x2 = a.publ;

a.publ_func(a.publ1);

x3 = a.prot; // Ошибка: обращение к защищенному члену класса

с4 = a.prot_func(a.priv); // Ошибка: обращение к защищенному методу класса и к закрытому члену класса

x4 = a.priv1; // Ошибка: обращение к закрытому члену класса

x5 = a.priv2; // Ошибка: обращение к закрытому члену класса

x6 = a.publ1;

x7 =

}

-------------------------------------------------------------------


Пример 3. Обращение к объектам класса из дружественной функции func2(): разрешены обращения к любым объектам класса (class A см.Пример 1)


void func2(int x) {

A a;

x1 = a.priv;

a.priv_func(a.publ);

a.publ_func(a.priv);

}

-------------------------------------------------------------------


2. Уровень доступа выведенного класса


class <имя производного класса> : <уровень доступа> <имя базового класса> {

// тело класса

};


Уровень доступа — это public (открытый), private (закрытый) или protected (защищенный), по умолчанию private.


public => все открытые и защищенные члены базового класса становятся открытыми и защищенными членами производного класса


private => все открытые и защищенные члены базового класса становятся закрытыми членами производного класса


protected => все открытые и защищенные члены базового класса становятся защищенными членами производного класса



Пример 4. Выведение класса (найдите ошибку в использовании private элемента и придумайте, как ее просто исправить):


class A {

int a;

public:

A(int aa):

a(aa)

{}

};

class B : A {

int b;

public:

B(int aa, int bb):

A(aa),

b(bb)

{ b = a * a; }

};


Как исправить:

1. Реализовать доступ к «a” (ввести функцию, возвращающую значение «a”)

2. Использовать «public” для определения доступа B к базовому классу

-------------------------------------------------------------------


Пример 5. Уровень доступа public:


#include <iostream>

using namespace std;


class base {

int i, j;

public:

void set(int a, int b) { i = a; j = b; }

void show() { cout << i << “ “ << j << “\n”; }

};


class derived: public base {

int k;

public:

derived(int x) { k = x; }

void showk() { cout << k << “\n”; }

};


int main() {

derived ob(3);


ob.set(1, 2); // обращение к методу класса base, так как set() определена только для base

ob.show(); // обращение к методу класса base, так как show() определена только для base


ob.showk(); // обращение к члену класса derived


return 0;

}

-------------------------------------------------------------------


Пример 6. Уровень доступа private (найдите отличие от примера 5):

// Эта программа не будет скомпилирована

#include <iostream>

using namespace std;


class base {

int i, j;

public:

void set(int a, int b) { i = a; j = b; }

void show() { cout << i << “ “ << j << “\n”; }

};


// Открытые члены класса base являются закрытыми членами класса derived

class derived: private base {

int k;

public:

derived(int x) { k = x; }

void showk() { cout << k << “\n”; }

};


int main() {

derived ob(3);


ob.set(1, 2); // Ошибка: доступ к функции set() запрещен

ob.show(); // Ошибка: доступ к функции show() запрещен


return 0;

}

-------------------------------------------------------------------


Пример 7. Уровень доступа protected:


#include <iostream>

using namespace std;


class base {

protected:

int i, j;

public:

void set(int a, int b) { i = a; j = b; }

void show() { cout << i << “ “ << j << “\n”; }

};


class derived: public base {

int k;

public:

void setk() { k = i * j; } // класс derived имеет доступ к членам i и j из класса base

void showk() { cout << k << “\n”; }

};


int main() {

derived ob(3);


ob.set(1, 2); // метод set() доступен классу derived

ob.show(); // метод show() доступен классу derived


ob.setk();

ob.showk();


return 0;

}

    Пример 8. Уровень доступа выведенного класса с уровнем доступа к базовому protected:


#include <iostream>

using namespace std;


class base {

int i, j;


protected:

int m;


public:

void set(int a, int b) { i = a; j = b; }

void show() { cout << i << “ “ << j << “\n”; }

};


class derived: protected base {

int k;

public:

void setk() { k = i * j; } // класс derived имеет доступ к членам i и j из класса base

void showk() { cout << k << “\n”; }

};


int main() {

derived ob(3);


ob.set(1, 2); // Ошибка: открытый метод set() недоступен для посторонних функций, так как уровень доступа выведенного класса - protected

ob.show(); // Ошибка: метод set() недоступен для посторонних функций, так как уровень доступа выведенного класса - protected


int tmp = ob.m; // Ошибка: защищенный член класса недоступен для посторонних функций, так как уровень доступа выведенного класса - protected

int tmp = ob.i; // Ошибка: закрытый член класса недоступен для посторонних функций, так как уровень доступа выведенного класса - protected


return 0;

}

-------------------------------------------------------------------


Доступ к объектам класса из методов выведенного класса при различных типах доступа наследования:



: public

: protected

: private

public:

+

+

+

protected:

+

+

+

private:

-

-

-



Доступ к объектам класса из посторонних функций при различных типах доступа наследования:



: public

: protected

: private

public:

+

-

-

protected:

-

-

-

private:

-

-

-



Задача для самостоятельного решения. Выяснить, можно ли добавить в описание библиотечного класса friend <имя функции> (и пользоваться этим в своей функции).