3.1. Простое наследование.
Простое наследование описывает родство между двумя классами: один из которых наследует второму. Класс, нахо дящийся на вершине иерархии, называется базовым классом. Прочие классы называются производными классами. Из одного класса могут выводится многие классы, но даже в этом случае подобный вид взаимосвязи остается простым наследованием.
Базовый класс часто называют предком, а производный класс — потомком.
Производный класс наследует из базового данные-члены и функции-члены, но не конструкторы и деструкторы.
class Tbase { //Базовый класс
private:
int count;
public:
TBase() {count = 0;}
void SetCount(int n) {count = n;}
int GetCount(void) {return count;}
};
class TDerived: public TBase { //Производный класс
public:
TDerived(): Tbase() {}
void ChangeCount(int n) {SetCount(GetCount() + n);}
};
Производный класс назван TDerived. За именем сле-дует двоеточие и одно из ключевых слов — public, protected, private. После этих элементов имя базового класса TBase. Открытые члены открытого класса остаются открытыми в производном классе:
class TDerived: public TBase {}
Все закрытые члены Tbase остаются закрытыми и в Tderived нельзя получить к ним доступ. Можно объявить базовый класс закрытым:
class TDerived: private TBase {}
Все открытые члены в базовом классе становятся закры-тыми в TDerived. Последующие наследования TDerived не смо-гут получить доступа в членам TBase. Обычно в производном классе есть конструктор, если он был в базовом. Он должен вызывать конструктор базового класса:
TDerived(): TBase() {}
Кроме этого в нем могут выполняться и другие действия, например:
TDerived():TBase() {cout <<" I am being initialized" <<endl;}
Можно реализовать объявленный конструктор отдельно:
TDerived::TDerived()
: TBase()
{ // операторы
}
Производный класс наследует count из базового класса, но так как он закрыт в TBase доступ к нему возможен только через функции-члены класса TBase. В производном классе можно определить функцию, которая будет обращаться к наследованным функциям-членам класса TBase:
void ChangeCount(int n) {SetCount(GetCount() +n);}
Защищенные члены класса — это нечто среднее между от-крытыми и закрытыми членами. Подобно закрытым они доступны только функциям-членам класса. Вне класса они недоступны. Подобно открытым они доступны функциям-членам производных классов.
— закрытые члены доступны только в том классе, в кото-ром они объявлены;
— защищенные члены доступны членам их собственного класса и всем членам производных классов;
— открытые члены доступны членам их собственного класса, членам производных классов и всем остальным пользователям этого класса.
Спецификаторы (public, private, protected) влияют на статус наследуемых членов:
— члены открытого базового класса в производном классе сохраняют свои спецификации доступа;
— открытые члены защищенного базового класса становятся закрытыми в производном классе. Защищенные и закрытые сохраняют свои первоначальные спецификации;
— все члены закрытого базового класса становятся закрытыми в производном классе независимо от их перво-начальной спецификации доступа.
Если хотите сделать открытыми в производном классе только некоторые из наследуемых членов, можно выбо-рочно квалифицировать один или несколько из них.
class A {
public:
int x;
A() { x=0;}
void Display(void) { count << "x = " << x << endl;}
};
class B: private A {
public:
A::Display; // квалифицируем как открытый член класса
B(): A() {}
};
В производном классе деструктор нужен только в том случае, если необходимо что-то удалять.
// Программа 1
#include <iostream.h>
#include <string.h>
class TBase { //Базовый класс
private:
char *basep;
public:
TBase(const char *s) {basep = strdup(s); }
~TBase() {delete basep;}
const char *GetStr(void) { return basep; }
};
class TDerived: public TBase { //Производный класс
private:
char *uppercasep;
public:
TDerived(const char* s): TBase(s) { uppercasep = strupr(strdup(s));}
~TDerived() {delete uppercasep;}
const char *GetUStr(void) { return uppercasep;}
};
void main()
{
TBase president("George Washington");
cout << "Original string: " << president.GetStr() << endl;
TDerived pres("George Washington");
cout << "Uppercase string:" << pres.GetUStr() << endl;
}
В производном классе обычно добавляются новые дан-ные и функции-члены. Однако существует возможность заме-щения функций-членов, наследованных от базового класса. Например:
//Программа 2
#include <iostream.h>
#include <string.h>
class TBase { //Базовый класс
private:
char *basep;
public:
TBase(const char *s) {basep = strdup(s); }
~TBase() {delete basep;}
void Display(void) { cout << basep << endl;}
};
class TState: public TBase { //Производный класс
public:
TState(const char *s):TBase (s) {}
void Display(void); // замещающая функция
};
void TState::Display(void)
{
cout << "State: "; //Новый оператор
TBase::Display(); //Вызов замещенной функции
}
void main()
{
TState object("Welcome to Borland C++5 programming!");
object.Display();
}
3.2. Множественное наследование
Построение производного класса на основе нескольких базовых выглядит очень просто: вместо имени одного базового класса (вместе с его атрибутом) используется список имен, разделенный запятыми, например:
class A { /*…*/ };
class B { /*…*/ };
class C: public A, private B { /*…*/ };
Передача аргументов конструкторам базовых классов из конструктора производного класса производится так же как и раньше:
С::С( int a, char* str) : A(a), B(str) { /*…*/ };