Рассмотрим программу имеющею дело с людьми, работающими в какой-то организации. Эта программа может иметь следующую структуру данных.
struct employee{
char *name; //ФИО
short age; //его номер
short department; //номер отдела
int salary; //зарплата
employee *next;
//…
};
поле next это связь в списке служащих одного ранга.
Теперь определим управляющего.
struct manager: employee{
employee *group;
//…
};
manager это служащий и данные employee запоминаются в базовом классе в качестве которого выступает класс employee, т.о. класс manager имеет члены класса employee дополнительно к члену класса group.
Имея определения employee и manager, мы можем создать список служащих некоторые из которых явл. управляющими
void f( ){
manager m1,m2;
employee e1,e2;
employee *elist;
elist = &m1; //помещение m1,e1,m2,e2 в elist
m1.next = &e1;
e1.next = &m2;
m2.next = &e2;
e2.next = 0;
Функции члены в производных классах.
Рассмотрим пример:
class employee{
char *name;
//…
public:
employee *next;
void print( );
//…
};
class manager : public employee{
//…
public:
void print( );
//…
};
К приведенному примеру возникает ряд вопросов и в частности как может М-функция произвольного класса manager использовать данные его базового класса employee.
Пример:
void manager::print( ){
cout<<””<<name<<”\n”;
//…
};
В данном примере manager::print( ) не будет компилироваться т.к. член производного класса не имеет специального разрешения чтобы получить личные данные его базового класса, поэтому name ему недоступно (ограничение доступа это защита от беспорядочного использования данных). Для обеспечения доступа либо к заданным функциям либо к каждой функции заданного класса можно использовать механизм friend.
class employee{
friend void manager::print( );
//…
};
class employee{
friend class manager;
//…
};
альтернативное решение это использование для производного класса только открытых членов его базового класса.
void manager::print( ){
employee::print( );
//…
}
Видимость.
Для упорядочивания процедуры доступа к элементам производных классов вводят защищенные члены классов.
5/
Видимость.
Для упорядочивания процедуры доступа к элементам производных классов вводят защищенные члены классов.
Защищенный член класса это нечто среднее между защищенным и открытым членом. Подобно закрытым членам защищенные доступны только т-функциям класса.
Подобно открытым членам защищенные наследуются производными классами и доступны т-функциям производных классов.
Следует иметь ввиду следующие правила, при принятии решения делать ли член класса закрытым, защищенным или открытым.
Закрытые члены доступны только в классе, в котором они объявлены.
Защищенные члены доступны членам их собственного класса и всем членам производных классов.
Открытые члены доступны членам их собственного класса, членам производных классов и всем остальным пользователям этого класса.
Рассмотрим класс:
Class TAny Class{
private: //доступны только членам TAnyClass
int A;
void fa(void);
protected: //доступны TAanyClass и членам производных классов
int B;
void fb(void);
public: //доступно всем членам, кто его использует.
int C;
void fc(void); };
Спецификаторы доступа private, protected, public могут также предшествовать имени базового класса в объявлении производного класса:
Class TDerived : public TAny Class{ новые данные члены, т-функции и тд}
Указатели производных классов
class base{…};
class derived: pablic base {…};
……
derived m;
base *pb=&m; //неявное преобразование.
derived *pd=pb; //ОШИБКА base* не derived*
pd=(derived *)pb //явное преобразование.
Если производный класс derived имеет открытый базовый класс base, то указатель на derived может быть присвоен переменной типа указатель на base без явного преобразования типа, обратное преобразование должно быть явным.
Другими словами при обработке по средствам указателей объект производного класса может рассматриваться, как объект своего базового класса, противоположное не верно.
Наследование.
Производный класс сам может быть базовым классом:
class employee {…};
class secretary: employee{…};
class manager: employee{…};
class director: manager {…};
class vice_prinsedent: manager {…};
class president: vice_president {…};
Такой набор связанных классов традиционно называется – иерархия классов. В этом случае говорят, что производные и базовые классы связаныотношением простого наследования, при котором один класс может наследовать данные и m-ф-ции из других базовых классов. Рассмотрим пример множ. Наследования:
class temporary{ …};
class employee{…};
class secretary: employee {…};
class temporary_secretary: temporary, secretary {…};
Множественное наследование отличается лишь тем, что производный класс наследует все св-ва всех перечисленных базовых классов, в случае конфликта имен следует использовать оператор расширения видимости :: , например предположим, что классы А и В оаб имеют открытую ф-ю display. В производном классе
class D: public A, public B {
public: void f(void); };
В m-ф-ю f необходимо указать какую из конфликтующих ф-й display следует вызвать:
void D :: f(void) {
Display (); // не компилируется
A::Display(); // вызов ф-и А
B::Display();// вызов ф-и В
}
Констукторы и деструкторы в производных классах
Объекты производного класса, в качестве данных членов класса, могут содержать объекты абстрактных типов как базового, так и совершенно другого типа. Пример:
class String {
//…..
public:
String(char*);
~String();
//…
};
class Base {
//…
public:
Base (int);
~Base ();
//….
}
class Derived : public Base {
Base base;
String string;
Public:
Derived (char*int);
~Derived();
//…
};
Перед обращением к конструктору класса Derived необходимо:
1) Создать подобъект типа Base
2) члены base и string, поскольку для их создания нужно обратиться к конструкторам соответствующих классов мы должны им всем передать необходимые списки аргументов:
Derived:: Derived(char*str, int len):-
Base (len), Base (len+1), String (str) {
//….
}
В этом случае при создании объекта типа Derived сначала будет создан подобъект типа base, затем созданы объекты абстрактных типов base и string ( в том порядке, в котором они перечислены в определении класса Derived) и, наконец, будет выполнен конструктор Derived.
Деструкторы будут вызваны в обратном порядке.