Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

техпрог / Comp-Sci-09

.pdf
Скачиваний:
44
Добавлен:
10.02.2015
Размер:
650.58 Кб
Скачать

Материалы к лекции 9

Объектно-ориентированное программирование

МНОЖЕСТВЕННОЕ НАСЛЕДОВАНИЕ

Прямое и косвенное наследование

Пример. Прямое и косвенное наследование базового класса

// Twoclass0.cpp :

//

#include "stdafx.h" #include <iostream> using namespace std; class A {

int a; public:

A(int x) { a = x; }

int geta() { return a; }

};

// Прямое наследование базового класса class B : public A {

int b; public:

B(int x, int

y) : A(y)

// передача переменной y классу A

{

b = x;

}

 

int getb() {

return b;

}

};

//Прямое наследование производного класса

//и косвенное наследование базового класса class C : public B {

int c; public:

C(int x, int y, int z) : B(y, z) /* передача аргументов классу B */

{

c = x;

}

/* Поскольку базовые

классы наследуются как открытые, класс C

имеет доступ к открытым элементам классов A и B */ void show() {

cout << geta() << ' ' << getb() << ' '; cout << c << '\n';

}

};

int _tmain(int argc, _TCHAR* argv[])

{

C ob(1, 2, 3); ob.show();

// функции geta() и getb() здесь тоже открыты cout << ob.geta() << ' ' << ob.getb() << ' ';

return 0;

}

МНОЖЕСТВЕННОЕ НАСЛЕДОВАНИЕ

В C++ производный класс может иметь более одного базового класса. Например, так можно создать класс для фигуры Ферзь (см. пример в конце лекции)

// Класс Ферзь - наследник Ладьи и Слона class queen: public elephant, public castle

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

Правила доступа для множественного наследования те же, что и для простого наследования.

Пример. Производный класс наследует сразу два класса.

#include <iostream> using namespace std;

//Создание первого базового класса class B1 {

int a; public:

B1(int x) { a = x; }

int geta() { return a; }

};

//Создание второго базового класса class B2 {

int b; public:

B2(int x)

{b = x; }

int getb() { return b; }

};

// Прямое наследование двух базовых классов class D : public B1, public B2 {

int c; public:

//здесь переменные z и y

//напрямую передаются классам B1 и B2

D(int x, int y, int z) : B1(z), B2(y) { c = x; }

/* Поскольку базовые классы наследуются как открытые, класс D имеет доступ к открытым элементам классов B1 и B2

*/

void show() {

cout << geta() << ' ' << getb() << ' '; cout << c << '\n';

}

};

int main()

{

D ob(1, 2, 3); ob.show(); return 0;

}

Все конструкторы базового класса вызываются до вызова конструкторов производного класса. Располагаются они в том порядке, в котором базовые классы перечислены в объявлении производного класса.

Если в двух базовых классах совпадают имена элементов данных или методов, то объект производного класса содержит обе копии. C++ не имеет правил предшествования для доступа к данным и методам. Неоднозначность разрешается использованием явной квалификации.

Пример.

// TwoClass.cpp : Производный класс наследует два класса

//

#include "stdafx.h" #include <iostream> using namespace std;

//Создание первого базового класса class B1 {

int a; public:

B1(int x) { a = x; }

void f(){cout<<"\n f in B1 \n";} int geta() { return a; }

};

//Создание второго базового класса class B2 {

int b; public:

B2(int x) { b = x; }

void f(){cout<<"\n f in B2\n";} int getb() { return b; }

};

//Прямое наследование двух базовых классов class D : public B1, public B2 {

int c; public:

//здесь переменные z и y

//напрямую передаются классам B1 и B2

D(int x, int y, int z) : B1(z), B2(y)

{c = x; }

/* Поскольку базовые классы наследуются как открытые, класс D имеет доступ к открытым элементам классов B1 и B2

*/

void show() {

cout << geta() << ' ' << getb() << ' '; cout << c << '\n';

}

};

int _tmain(int argc, _TCHAR* argv[])

{

D ob(1, 2, 3); ob.show();

// ob.f(); // неоднозначность ob.B1::f();

ob.B2::f(); return 0;

}

Можно поступить иначе – создать методы в производном классе, вызывающие одноименные функции из базовых классов.

// Twoclass2.cpp :

//

#include "stdafx.h" #include <iostream> using namespace std;

//Создание первого базового класса class B1 {

int a; public:

B1(int x) { a = x; }

void f(){cout<<"\n f in B1 \n";} int geta() { return a; }

};

//Создание второго базового класса class B2 {

int b; public:

B2(int x) { b = x; }

void f(){cout<<"\n f in B2\n";} int getb() { return b; }

};

//Прямое наследование двух базовых классов class D : public B1, public B2 {

int c; public:

//здесь переменные z и y

//напрямую передаются классам B1 и B2

D(int x, int y, int z) : B1(z), B2(y)

{c = x; }

/* Поскольку базовые классы наследуются как открытые, класс D имеет доступ к открытым элементам классов B1 и B2

*/

void show() {

cout << geta() << ' ' << getb() << ' '; cout << c << '\n';

}

void fb1(){B1::f();} void fb2(){B2::f();}

};

int _tmain(int argc, _TCHAR* argv[])

{

D ob(1, 2, 3); ob.show();

// ob.f(); // неоднозначность ob.fb1();// вместо ob.B1::f(); ob.fb2();//вместо ob.B2::f();

return 0;

}

Иерархия классов при множественном наследовании представляет собой граф, в простом наследовании – дерево.

Пример. В этой программе, чтобы избежать появления в классе derived3 двух копий класса base, используется виртуальный базовый класс

#include <iostream> using namespace std; class base {

public: int i;

};

// Наследование класса base как виртуального class derived1 : virtual public base { public:

int j;

};

// Здесь класс base тоже наследуется как виртуальный class derived2 : virtual public base {

public: int k;

};

/* Здесь класс derived3 наследует как класс derived1, так и класс derived2. Однако в классе derived3 создается только одна копия класса base

*/

class derived3 : public derived1, public derived2 { public:

int product() { return i * j * k; }

};

int main()

{

derived3 ob;

//Здесь нет неоднозначности, поскольку

//представлена только одна копия класса base

ob.i = 10; ob.j = 3; ob.k = 5;

cout << "Poluchili resultat = " << ob.product() << '\n'; return 0;

}

Пример. (см. Открытые системы №5-6, 2001 – www.osp.ru)

#include <iostream> #include <cmath> using namespace std;

//Использование множественного наследования для создания ферзя

//из слона и ладьи

enum coord1 {a ,b ,c, d, e, f, g, h}; // горизонталь

enum color {black, white};

//цвет фигуры

//Фигура - общий предок всех остальных class figure {

protected:

coord1 letter; // координата a..h int digit; // координата 1..8 color fig_color; // цвет фигуры

public: //конструктор

figure(coord1 x, int y, color z) : letter(x), digit(y), fig_color(z)

{} //чистая функция "ход"

virtual bool step (coord1 new_letter, int new_digit)=0;

};

//Класс Ладья реализует функцию "ход" class castle: public virtual figure {

public:

castle(coord1 x, int y, color z): figure (x, y, z){} bool step(coord1 new_letter, int new_digit)

{

if ( ((new_letter == letter)&& (new_digit != digit))|| ((new_letter != letter)&& (new_digit == digit)))

{

letter = new_letter; digit = new_digit;return true;

}

return false;

}

};

//Класс Слон реализует свою функцию "ход"

class elephant: public virtual figure

{

public:

elephant(coord1 x, int y, color z): figure (x, y, z){} bool step(coord1 new_letter, int new_digit)

{

if (abs((new_letter - letter)== abs(new_digit - digit))&& (new_letter != letter))

{ letter = new_letter; digit= new_digit; return true;} return false;

}

};

// Класс Ферзь - наследник Ладьи и Слона class queen: public elephant, public castle

{

public: //конструктор

queen(coord1 x, int y, color z): castle (x, y, z), elephant(x, y, z),

figure (x, y, z)

{

}

bool

step(coord1 new_letter, int new_digit)

{

return castle::step(new_letter,new_digit)||

elephant::step(new_letter,new_digit);}

};

 

 

 

 

void

main(){

 

 

queen q(e, 5, white);

 

cout

<<

q.step(h, 8)

<< endl;

cout

<<

q.step(e, 8)

<< endl;

cout

<<

q.step(h, 8)

<< endl;

cout

<<

q.step(h, 5)

<< endl;

cout

<<

q.step(a, 8)

<< endl;

cout

<<

q.step(d, 8)

<< endl;

cout

<<

q.step(c, 5)

<< endl;

cout

<<

q.step(a, 1)

<< endl;

}

 

 

 

 

Соседние файлы в папке техпрог