Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать
70

a.a_3(); B b; b.b_3();

Cc; c.c_3();

Dd; d.a_3();

//d.b_3(); // b_3 cannot access public member declared in class 'B'

//d.c_3(); // c_3 cannot access public member declared in class 'C'

Ee;

ыдущего пункта приводит к формированию объекта av и вызова конструктора

avt производного класса и конструктора book б зового класса (предыдущая

программа):

а

 

к

e.d_3();

 

Р

e.e_1();

 

return 0;

 

}

 

И

4.1.1. Конструкторы и деструкторы при наследовании

Инструкция avt av("книга

1",123," автор 1") в примереУпрограммы пред-

 

Г

 

 

Б

 

void avt::avt(char *s1,int i,char *s2) : book(s1,i)

няется инициализация компонент-данных naz и kl), затем конструктор произ- водного класса avt (инициализация компон нты fm). Поскольку базовый класс

При этом вначале вызывается конструего тор б зового класса book (выпол-

ничего не знает про производные от н

классы, его инициализация (вызов его

о

 

 

конструктора) производится перед инициализацией (активизацией конструкто-

ра) производного класса.

 

 

и

 

производного класса вызывается

В противоположность эт мутруктордес

перед вызовом деструктора баз вого класса. Это объясняется тем, что уничто- жение объекта азового к асса влечет за собой уничтожение и объекта произ-

водного класса, с едовате ьно, деструктор производного класса должен выпол-

няться перед деструкторомл

базового класса.

 

Ниже

ведена программа вычисления суммы двух налогов, в которой ис-

 

 

б

 

пользована следующая форма записи конструктора базового и производного клас-

сов.

при

 

 

имя конструктора(тип переменной_1 имя_переменной_1,…,

 

Б

тип переменной_n имя_переменной_n) :

 

 

 

 

имя_конструктора_базового_класса(имя_переменной_1,…, имя_переменной_k),

 

компонент_данное_1(имя_переменной_m),…,

 

компонент_данное_n(имя_переменной_n);

 

#include "iostream"

 

 

using namespace std;

// базовый класс

 

class A

 

pr2(prc2). Аналогично конструктор В считывает из стека 2 double значения prc1

{

 

protected:double pr1,pr2;

// protected для видимости pr в классе B

public:

 

 

 

 

 

 

 

 

 

 

 

A(double prc1,double prc2): pr1(prc1),pr2(prc2) {};

 

 

};

 

void a_prnt(){cout << "% налога = " << pr1 << " и " << pr2 << endl;}

 

 

 

 

 

 

// производный класс

 

class B : public A

 

 

{

 

int sm;

 

 

 

 

 

 

 

 

public:

 

 

 

 

 

 

 

 

 

 

 

B(double prc1,double prc2,int sum): A(prc1,prc2),sm(sum) {};

 

 

void b_prnt()

 

 

 

 

 

 

 

 

{ cout << " налоги на сумму = " << sm << endl;

 

 

 

 

cout << "первый = " << pr1 <<"\n втрой = " << pr2 << endl;

 

 

}

 

 

 

 

 

 

 

 

Р

};

 

double rashet() {return pr1*sm/100+pr2*sm/100;}

И

 

main()

 

 

 

 

 

 

int

 

 

 

 

 

 

У

 

{ A aa(9,5.3);

 

 

 

 

 

 

// описание объекта аа (базового класса) и инициа-

 

 

 

 

 

 

// лизация его компонентГс использованием

 

 

 

 

 

 

// конструкт

 

А()

 

 

 

B bb(7.5,5,25000); // описание объектаБbb (производного класса)

 

 

 

 

 

 

// и иници лиз ция его компонент (вызов конструк-

 

 

 

 

 

 

// тора B() и

онструктора А() (первым))

aa.a_prnt();

 

 

ора

 

 

 

 

 

к

 

 

 

 

bb.b_prnt();

 

 

 

 

 

 

cout << "Сумма налогае= " << bb.rashet() << endl;

 

 

return 0;

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

В приведенн м примеретиспользованы функции-конструкторы следующе-

го вида:

 

 

 

о

 

 

 

 

 

 

public: A(double prc1,double prc2): pr1(prc1),pr2(prc2) {};

 

 

 

 

и

 

 

 

 

 

 

public: B(double prc1,double prc2,int sum): A(prc1,prc2),sm(sum) {};

Конструкторл

А считывает из стека 2 double значения prc1 и prc2, которые

далее

 

спользуются для инициализации компонент класса А pr1(prc1),

б

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

 

и prc2 и одно значение int, после чего вызывается конструктор класса

A(prc1,prc2), затем выполняется инициализация компоненты sm класса В.

Б

Производный класс может служить базовым классом для создания сле-

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

71

щаемого значения и сигнатурой, как и у функции-компоненты базового класса, но с новой реализацией, то эта функция считается переопределенной. Под сиг- натурой понимают имя функции со списком параметров, заданных в ее прото- типе, а также слово const. Типы возвращаемых значений могут различаться.

Ниже приведен текст еще одной программы, в которой также использует- ся наследование. В программе выполняется преобразование арифметического выражения из обычной (инфиксной) формы в форму польской записи. Для это- го используется стек, в который заносятся арифметические операции. Алгоритм

преобразования выражения здесь не рассматривается.

 

 

 

Р

#include<iostream>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

И

using namespace std;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include<stdlib.h>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

class st

 

 

 

 

 

 

// класс «элемент стека операций»

 

{ public :

 

 

 

 

 

 

 

 

 

 

 

 

Г

 

 

 

char c;

 

 

 

 

 

 

 

 

 

 

 

Б

У

 

 

st *next;

 

 

 

 

 

 

 

 

 

 

 

 

public:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

st(){}

 

 

//

конструктор

 

 

а

 

 

 

 

 

~st(){}

 

//

деструктор

 

 

 

 

 

 

 

};

 

 

 

к

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

class cl : public st

 

 

 

 

// класс преобр зования выражения

 

{

char *a;

 

 

 

 

 

//

 

исходная строка (для анализа)

 

 

char outstr[80];

 

 

 

т

 

 

 

 

 

 

 

 

 

 

 

 

//

 

выходная строка

 

 

 

 

public :

 

 

//

 

 

 

 

 

е

 

 

 

 

 

 

 

cl() : st() {}

к с рук ор

 

 

 

 

 

 

 

 

 

~cl(){}

 

//

деструк

р

 

 

 

 

 

 

 

 

 

 

 

 

 

 

и

 

//

занесение символа в стек

 

 

};

st *push(st *,char);

 

 

 

 

 

 

 

л

он//

извлечение символа из стека

 

 

 

char pop(st **);

 

 

 

 

 

int PRIOR(char);

 

 

 

//

 

определение приоритета операции

 

 

 

б

 

 

 

 

//

преобразование в польскую запись

 

 

char *ANALIZ(char *);

 

 

 

и

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

char * cl::ANALIZ(char *aa)

 

 

 

 

 

 

 

 

 

 

 

 

Б

 

 

 

 

 

 

//

 

 

 

 

 

 

 

 

 

 

{ st *OPERS;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

OPERS=NULL;

 

 

 

 

// стек операций пуст

 

 

 

 

int k,p;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

a=aa;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k=p=0;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

while(a[k]!='\0'&&a[k]!='=')

 

 

 

// пока не дойдем до символа '='

{ if(a[k]==')')

 

 

 

 

 

 

 

// если очередной символ ')'

 

 

{ while((c=pop(&OPERS))!='(') // считываем из стека в выходную

 

 

outstr[p++]=c;

 

 

 

 

 

 

 

// строку все знаки операций до символа

72

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

// ‘(‘ и удаляем из стека ‘(‘

 

 

 

 

 

 

 

 

 

 

 

if(a[k]>='a'&&a[k]<='z')

 

// если символ буква, то

 

 

outstr[p++]=a[k];

 

 

// заносим ее в выходную строку

 

 

if(a[k]=='(')

 

 

 

//

если очередной символ '(' , то

 

 

OPERS=push(OPERS,'(');

//

помещаем его в стек

 

 

if(a[k]=='+'||a[k]=='-'||a[k]=='/'||a[k]=='*')

 

 

 

{

 

 

 

// если следующий символ знак операции, то

 

 

 

while((OPERS!=NULL)&&(PRIOR(c)>=PRIOR(a[k])))

 

 

 

outstr[p++]=pop(&OPERS); // переписываем в выходную строку все

 

 

 

 

 

 

//

находящиеся в стеке операции с большим

 

 

 

 

 

 

//

или равным приоритетом

 

 

 

OPERS=push(OPERS,a[k]); // записываем в стек очереднуюРоперацию

 

 

}

 

 

 

 

 

 

 

У

 

 

 

 

 

 

 

 

 

Г

 

 

k++;

 

// переход к следующему символуИвыходной строки

 

 

}

 

 

 

 

 

 

 

 

 

 

while(OPERS!=NULL)

// после анализа всего выражения

 

 

outstr[p++]=pop(&OPERS); //

переписываем операции из стека

 

 

outstr[p]='\0';

 

 

//

в выходную строку

 

}

return outstr;

 

 

к

Б

 

 

 

 

 

 

 

 

 

 

 

 

 

 

е

 

 

 

 

 

 

 

 

 

 

 

 

 

st *cl::push(st *head,char a)

// фунация записи символа в стек и возврата

 

{ st *PTR;

 

т

// у азателя на вершину стека

 

 

if(!(PTR=new st))

 

 

 

 

 

 

}

{ cout << "\n нед с а очно памяти для элемента стека"; exit(-1);}

 

 

 

о

// инициализация элемента стека

 

 

 

PTR->c=a;

 

 

 

 

и

 

 

 

 

 

 

 

 

 

PTR->next=head;

 

 

 

 

 

 

 

 

return PTR;

 

// PTR – вершина стека

 

 

 

 

л

 

 

// функция удаления символа с вершины стека

 

char cl::pop(st **head)

 

{ st *PTR;

 

 

// возвращает символ (с вершины стека) и коррек-

и

 

 

 

// тирует указатель на вершину стека

Б

бchar a;

 

 

 

 

// если стек пуст, то возвращается ‘\0'

 

 

if(!(*head)) return '\0';

 

 

PTR=*head;

 

// адрес вершины стека

 

 

 

a=PTR->c;

 

 

// считывается содержимое с вершины стека

 

 

*head=PTR->next; // изменяем адрес вершины стека (nex==PTR->next)

 

 

delete PTR;

 

 

 

 

 

 

return a;

}

int cl::PRIOR(char a) // функция возвращает приоритет операции

{ switch(a)

73

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]