Fish(bool IsFreshWater) : FreshWaterFish(IsFreshWater){}
void Swim()
{
if (FreshWaterFish)
cout « "Swims in lake" « endl;
else
1": cout « "Swims in sea" « endl;
Is: }
};
class Tuna: public Fish
22: {
public:
Tuna(): Fish(false) {}
};
2": class Carp: public Fish
2=: {
public:
Carp() : Fish(true) {}
:1: };
2: int main()
:4: {
Carp myLunch;
Tuna myDinner;
|
cout
|
«
|
"Getting my food to swim" «
|
endl;
|
*]:
|
cout
|
«
|
"Lunch:
|
";
|
|
-1:
|
myLunch.Swim();
|
|
|
-2:
|
cout
|
«
|
"Dinner:
|
";
|
|
-4:
|
myDinner.Swim();
|
|
|
*5:
|
// Снимите комментарий со строки 48,
|
чтобы убедиться в
|
недоступности защищенных членов извне иерархии класса
myLunch.FreshWaterFish = false;
:2: return 0;
-1: }
256 ЗАНЯТИЕ 10. Реализация наследования
Результат
Getting my food to swim
Lunch: Swims in lake
Dinner: Swims in sea
Анализ
Теперь у класса F is h есть конструктор, который получает заданный по умолчанию па раметр, инициализирующий переменную F i s h : : F re sh W a te rF ish . Таким образом, един ственная возможность создать объект класса F is h — это предоставить параметр, который
инициализирует защищенный член. Так, класс F is h гарантирует, что защищенный член класса не будет содержать случайного значения, если пользователь производного клас са забудет его установить. Теперь производные классы Tuna и C arp вынуждены опреде лить конструктор, создающий экземпляр базового класса F is h с правильным параметром ( t r u e или f a l s e , указывающим, пресноводная ли это рыба), как показано в строках 24 и 30 соответственно.
ПРИМЕЧАНИЕ
Как можно заметить в листинге 10.3, производный класс никогда не обращался непосредственно к логической переменной-члену Fish::FreshWaterFish, несмотря на то, что она является защищенной, поскольку ее значение было установлено конструктором класса Fish.
Чтобы гарантировать максимальную защиту, если производные классы не нуж даются в доступе к атрибуту базового класса, отметьте его как private.
Производный класс, переопределяющий методы базового класса
Если производный класс реализует те же функции с теми же возвращаемыми значе ниями и сигнатурами, что и базовый класс, от которого он происходит, то он фактически переопределяет этот метод базового класса, как показано в следующем коде:
class Base
{
public:
void DoSomething()
{
// код реализации... Делает нечто
}
class Derived:public Base
{
public:
void DoSomething()
{
// код реализации... Делает нечто другое
Таким образом, если бы метод D oSom ething () должен быть вызван с использованием экземпляра класса D e riv e d , то это не задействовало бы функциональные возможности в классе B ase.
Если классы Tuna и C a rp должны реализовать собственный метод Sw im (), который существует также и в базовом классе как F i s h : : Swim (), то его вызов в методе m ain () так, как показано в следующем отрывке листинга 10.3,
Tuna myDinner; // ... другие строки
myDinner.Swim();
привел бы к выполнению локальной реализации метода T u n a : : Swim (), которая, по ущ еству, переопределяет метод F i s h : : Swim () базового класса. Это демонстрирует ли-гтинг 10.4.
ЛИСТИНГ 10.4. Производные классы Tuna и Carp, переопределяющие метод SwimQ базового класса Fish
.: #include
using namespace std;
class Fish
{
private:
bool FreshWaterFish;
3: public:
// конструктор класса Fish
Fish(bool IsFreshWater) : FreshWaterFish(IsFreshWater){}
.1: void Swim()
{
.4: if (FreshWaterFish)
cout « "Swims in lake" « endl;
.5:else
cout « "Swims in sea" « endl;
}
};
class Tuna: public Fish
{
public:
Tuna(): Fish(false) {}
void Swim()
1": {
cout « "Tuna swim^ real fast" « endl;
class Carp: public Fish
public:
Carp(): Fish (true) {}
1 3ak. 3626
листинге 10.5 показан вызов члена базового класса с использованием экземпляра гроизводного класса.
Вызов методов базового класса в производном классе
Обычно метод F i s h : : Swim () содержал бы обобщенную реализацию плавания, при менимого ко всем рыбам, включая тунцов и карпов. Если специализированные реализации методов T u n a :: Swim () и C a rp : : Swim () должны использовать обобщенную реализацию метода базового класса F i s h :: Swim (), используйте оператор области видимости ( : : ) , как ю казано в следующем коде:
class Carp: public Fish
{
public:
Carp(): Fish(true) {}
void Swim()
{
cout « "Carp swims real slow" « endl;
Fish::Swim(); // использование оператора области видимости ::
Этот подход используется в листинге 10.5.
ЛИСТИНГ 10.5. Использование оператора области видимости (::) для вызова методов базового класса из методов производных классов и функции main ()
*: #include
using namespace std;
class Fish
private:
bool FreshWaterFish;
8: public:
// конструктор класса Fish
.1: Fish(bool IsFreshWater) : FreshWaterFish(IsFreshWater){}
.2: void Swim()
-3: {
if (FreshWaterFish)
cout « "Swims in lake" « endl;
else
1": cout « "Swims in sea" « endl;
}
1 *: } ;
class Tuna: public Fish
{
public:
Tuna(): Fish(false) {}
260 ЗАНЯТИЕ 10. Реализация наследования
void Swim()
{
cout « "Tuna swims real fast" « endl;
}
};
31:
class Carp: public Fish
{
public:
Carp(): Fish(true) {}
void Swim()
{
cout « "Carp swims real slow" << endl;
Fish::Swim();
}
};
43:
int main()
{
Carp myLunch;
Tuna myDinner;
cout « "Getting my food to swim" « endl;
cout « "Lunch: ";
myLunch.Swim();
53:
cout « "Dinner: ";
myDinner.Fish::Swim();
return 0;
}
Результат
Getting my food to swim
Lunch: Carp swims real slow
Swims in lake
Dinner: Swims in sea
Анализ
Метод C a rp : : Swim () в строках 37-41 демонстрирует вызов функции F i s h : : Swim () базового класса с использованием оператора области видимости ( : : Строка 55, с другой стороны, демонстрирует возможность использования оператора области видимости ( : : ) для вызова метода базового класса F i s h : : Swim () из функции m ain () с использованием объекта производного класса, в данном случае Tuna.
Do'stlaringiz bilan baham: |