Конструкторы производного класса — КиберПедия 

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

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

2020-05-08 209
Конструкторы производного класса 0.00 из 5.00 0 оценок
Заказать работу

Это потенциальная проблема в программе COUNTEN. Что будет, если мы захотим инициализировать значением объект класса CountDn? Сможем ли мы воспользо­ваться конструктором класса Counter с одним аргументом? Ответ будет отрица­тельным. Как мы видели в программе COUNTEN, компилятор будет использовать конструктор базового класса без аргументов. Мы должны написать новый конст­руктор для производного класса. Это показано в программе C0UNTEN2:

// counten2.cpp

// конструкторы в производных классах

#include <iostream>

using namespace std;

///////////////////////////////////////////////////////////

class Counter

{

protected: // заметьте, что тут не следует использовать private

unsigned int count;    // счетчик

public:

Counter (): count () // конструктор без параметров

{ }

Counter (int с): count (с) // конструктор с одним параметром

{ }

unsigned int get_count() const

{ return count; }// получение значения

Counter operator++ () // оператор увеличения

{ return Counter (++count); }

};

//unsigned int Counter::get_count () const // получение значения

//{ return count; }

///////////////////////////////////////////////////////////

class CountDn: public Counter

{

public:

CountDn (): Counter () // конструктор без параметров

{ }

CountDn (int с): Counter (с)// конструктор с одним параметром

{ }

CountDn operator-- () // оператор уменьшения

{ return CountDn (--count); }

};

///////////////////////////////////////////////////////////

int main ()

{

CountDn c1; // переменные класса CountDn

CountDn c2(100);

cout << "\nc1 = " << c1.get_count (); // выводим значения на экран

cout << "\nc2 = " << c2.get_count ();

++c1; ++c1; ++c1; // увеличиваем c1

cout << "\nc1 = " << c1.get_count (); // показываем результат

--c2; --c2; // уменьшаем c2

cout << "c2 = " << c2.get_count (); // показываем результат

CountDn c3 = --c2;    // создаем переменную сЗ на основе с2

cout << "\nсЗ = " << c3.get_count (); // показываем значение

cout << endl;

return 0;

}

 Программа использует два новых конструктора класса CountDn. Это конст­руктор без аргументов:

CountDn (): Counter () { }

В этом конструкторе использована новая для нас возможность: имя функ­ции, следующее за двоеточием. Она используется конструктором класса CountDn для вызова конструктора Counter() базового класса. Когда мы запишем в функ­ции main()

CountDn cl:

компилятор создаст объект класса CountDn и вызовет конструктор класса CountDn для его инициализации. Конструктор в свою очередь вызовет конструктор клас­са Counter, который выполнит нужные действия. Конструктор CountDn() может выполнять и свои операции, кроме вызова другого конструктора, но в нашем случае это не требуется, поэтому пространство между скобками пусто.

Вызов конструктора в списке инициализации может быть лишним, но это имеет смысл. Мы хотим инициализировать поле, не важно, принадлежит оно базовому или производному классу, и перед выполнением любого оператора программы сначала будут выполнены операции конструктора.

В строке

CountDn с2 (100):

функции main() используется конструктор класса CountDn с одним аргументом. Этот конструктор вызывает соответствующий конструктор с одним аргументом из базового класса:

CountDn (int с): Counter (с) // параметр с передается в конструктор класса Counter { }

Такая конструкция означает, что аргумент с будет передан от конструктора CountDn() в Counter(), где будет использован для инициализации объекта.

В функции main() после инициализации объектов cl и с2 мы увеличиваем один из них и уменьшаем другой, а затем выводим результат. Конструктор с од­ним аргументом также используется в выражениях присваивания:

CountDn сЗ = --с2:

 

Перегрузка функций

Мы можем определять для производного класса методы, имеющие такие же име­на, как и у методов базового класса. В этом случае имеет место перегрузка функ­ций. Такая возможность может понадобиться, если для объектов базового и про­изводного классов в вашей программе используются одинаковые вызовы.

Рассмотрим пример, основанный на программе STAKARAY из главы 7 «Масси­вы и строки». Эта программа моделировала стек, простое устройство хранения данных. Она позволяла помещать числа в стек, а затем извлекать их. При по­пытке отправить в стек слишком много чисел программа могла зависнуть по причине переполнения массива st [ ]. А при попытке извлечения количества чисел, большего, чем находится в стеке, результат мог быть бессмысленным, так как начинали считываться данные, расположенные в памяти за пределами массива.

Для исправления этих дефектов мы создадим новый класс Stack2, производ­ный от Stack. Объекты класса Stack2 ведут себя так же, как объекты класса Stack, за исключением того, что мы будем предупреждать о попытке переполнить стек или извлечь число из пустого стека. Вот листинг программы STAKEN:

// staken.cpp

// перегрузка функций базового и производного классов

#include <iostream>

using namespace std;

#include <process.h>  // для exit ()

///////////////////////////////////////////////////////////

class Stack {

protected: // Замечание: использовать private нельзя

enum { MAX = 3 }; // размер стека

int st[ MAX ];    // данные, хранящиеся в стеке

int top;    // индекс последнего элемента в стеке

public:

Stack () // конструктор

{ top = -1; }

void push (int var) // помещение числа в стек

{ st[ ++top ] = var; }

int pop () // извлечение числа из стека

{ return st[ top-- ]; }

};

///////////////////////////////////////////////////////////

class Stack2: public Stack

{

public:

void push (int var)   // помещение числа в стек

{

if (top >= MAX - 1) // если стек полон, то ошибка

{ cout << "\nОшибка: стек полон";

exit (1); }

Stack::push (var); // вызов функции push класса Stack

}

int pop () // извлечение числа из стека

{

if (top < 0) // если стек пуст, то ошибка

{ cout << "\nОшибка: стек пуст\п";

exit (1); }

return Stack::pop (); // вызов функции pop класса Stack

}

};

///////////////////////////////////////////////////////////

int main () {

Stack2 s1;

s1.push (11); // поместим в стек несколько чисел

s1.push (22);

s1.push (33);

cout << endl << s1.pop (); // заберем числа из стека

cout << endl << s1.pop ();

cout << endl << s1.pop ();

cout << endl << s1.pop (); // ой. а данных-то больше нет

cout << endl;

return 0;

}

В этой программе класс Stack тот же, что и в программе STAKARAY, за исклю­чением того, что данные класса объявлены как protected.

 


Поделиться с друзьями:

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

Опора деревянной одностоечной и способы укрепление угловых опор: Опоры ВЛ - конструкции, предназначен­ные для поддерживания проводов на необходимой высоте над землей, водой...

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

Историки об Елизавете Петровне: Елизавета попала между двумя встречными культурными течениями, воспитывалась среди новых европейских веяний и преданий...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.013 с.