Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lucik_op.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
2.88 Mб
Скачать

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

Инструкция avt av("книга  1",123," автор 1") в примере программы предыдущего пункта приводит к формированию объекта av и вызова конструктора avt производного класса и конструктора book базового класса (предыдущая программа):

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

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

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

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

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

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

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

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

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

#include "iostream.h"

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

{ 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;}

};

void main()

{ A aa(9,5.3); // описание объекта аа (базового класса) и инициа-

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

// конструктора А()

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

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

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

aa.a_prnt();

bb.b_prnt();

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

}

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

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),pr2(prc2). Аналогично конструктор В считывает из стека 2 double значения prc1 и prc2 и одно значение int, после чего вызывается конструктор класса A(prc1,prc2), затем выполняется инициализация компоненты sm класса В.

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

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

#include<iostream.h>

#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; // строку все знаки операций до символа

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

}

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;

if(!(*head)) return '\0'; // если стек пуст, то возвращается ‘\0'

PTR=*head; // адрес вершины стека

a=PTR->c; // считывается содержимое с вершины стека

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

delete PTR;

return a;

}

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

{ switch(a)

{ case '*':case '/':return 3;

case '-':case '+':return 2;

case '(':return 1;

} return 0;

}

void main()

{ char a[80]; // исходная строка

cl cls;

cout << "\nВведите выражение (в конце символ '='): ";

cin >> a;

cout << cls.ANALIZ(a) << endl;

}

В результате работы программы получим:

Введите выражение (в конце символ '=') : (a+b)-c*d=

ab+cd*-

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