Пример построения системы классов
Известно, что при объявлении массивов в Си/Си++ количество элементов массива задается константой и в дальнейшем не может быть изменено. При обращении к элементам массив отсутствует контроль выхода за пределы индексов массива, что приводит к трудно обнаруживамым ошибкам в программах. Построим систему классов для обработки динамических массивов, в которые можно добавлять новые элементы и исключить возможность выхода за пределы текущего размера массива. Общие свойства массивов с такими сойствами, не зависящие от типа элементов массива, объединим в классе TBase, а для массивов с различными типами элеменов образуем свои классы. Описания классов объединим в файле заголовков TBASEARR.H, а определения методов приведем в файле TBASEARR.CPP.
// файл TBASEARR.H#include <string.h>#include <iostream.h> class TBase //базовый класс для массивов всех типов {int size, //размер элемента count, //текущее число элементов maxCount, //размер выделенной памяти в байтах delta; //приращение памяти в байтах char *pmem; //указатель на выделенную память int changeSize(); //перераспределение памяти protected: void* getAddr( ){return (void*) pmem;}; void addNewItem(void*); //добавление в конец массива void error(const char* msg){cout <<msg<<endl;}; public: int getCount() {return count;}; TBase(int s,int m,int d); TBase(); TBase(TBase&); ~TBase(); }; /* Массив с элементами типа int */ class TIntArray: public TBase { public: int getElem(int index); // Значение элемента по индексу void putElem(int index,int &pe); // Замена значения элемента по индексу void addElem(int& el); // Добавление элемента в конец массива TIntArray& add(TIntArray&); // Сложение двух массивов поэлементно TIntArray& subtract(TIntArray&); // Вычитание массивов void printElem(int index); // Вывод значения элемента на экран void print(); // Вывод на экран всего массива TIntArray(int m,int d):TBase((int)sizeof(int),m,d){ }; /*Конструктор */ TIntArray(TBase& a):TBase( a ){}; /*Конструктор */ ~TIntArray(); };Определения методов приведены в файле TBASEARR.CPP:
|
|
Виртуальные функции
Понятие о “позднем” связывании
При описании объектных типов функции, имеющие сходное назначение в разных классах, могут иметь одинаковые имена, типы параметров и возвращаемого значения. При обращении к такой функции с указанием имени объекта компилятору известно, какая из одноименных функций требуется. В то же время к объектам производного типа можно обращаться по указателю на базовый тип и тогда на этапе компиляции нельзя установить, функция какого из производных типов должна быть вызвана. В ходе выполнения программы требуется проверять, на объект какого типа ссылается указатель и после такой проверки вызывать требуемую функцию. Эти действия называют “поздним” связыванием, в отличие от “раннего” связывания, при котором уже на этапах компиляции или редактирования связей можно установить адрес точки входа вызываемой функции. В объектно-ориентированных языках программирования для решения этой проблемы применяются виртуальные методы.
|
|
Описание виртуальных функций
Функция-компонента класса объявляется как виртуальная указанием ключевого слова virtual. Функции-компоненты в производных классах, заменяющие виртуальную функцию базового класса должны объявляться с тем же именем, тем же списком параметров и типом возвращаемого значения, что и соответствующая функция базового класса. Если из производного класса не образуется новых производных классов, ключевое слово virtual в описании функции можно опустить.
|
|
Если в производном классе нет объявления функции с тем же именем, что и виртуальная функция базового класса, будет вызываться функция базового класса.
Виртуальная функция может быть объявлена в форме:
virtual void print ( ) = 0;Такая функция называется “чистой” (pure) виртуальной функцией, а объектный тип, содержащий ее объявление, называется абстрактным объектным типом. В программе не могут создаваться экземпляры абстрактных типов, такой тип может использоваться только для образования производных типов, причем в производном типе следует либо снова определить эту виртуальную функцию как чистую, либо обявить ее как обычную виртуальную функцию, выполняющую конкретные действия.
Виртуальные функции особенно полезны, когда к методом класса требуется обращаться через указатель на экземпляр класса, а сам этот указатель имеет тип указателя на базовый класс. Пусть, например, в классе TBase объявлена чистая виртуальная функция print:
class TBase //базовый класс для массивов всех типов {int size, //размер элемента count, //текущее число элементов maxCount, //размер выделенной памяти в байтах delta; //приращение памяти в байтах char *pmem; //указатель на выделенную память int changeSize(); //перераспределение памяти protected: void* getAddr( ){return (void*) pmem;}; void addNewItem(void*); //добавление в конец массива void error(const char* msg){cout <<msg<<endl;}; public: int getCount() {return count;}; TBase(int s,int m,int d); TBase(); TBase(TBase&); ~TBase(); virtual void print ( ) = 0; // Чистая виртуальная функция };Тогда в производных классах должна быть объявлена замещающая ее функция print, выполняющая реальные действия:
|
|
В программе, использующей объекты классов TIntArray и TRealArray могут создаваться экземпляры этих классов с возможностью обращения к ним через указатель на базовый класс:
TBase *pb; TIntArray aint(5,3); TRealArray areal(4,2);Тогда для печати массивов могут применяться операторы
pb = &aint; pb->print(); //Печать массива aint pb = &areal; pb->print(); // Печать массива arealПриведем еще один пример использования виртуальных функций. Пусть некоторый любитель домашних животных решил завести каталог своих любимцев и для каждого вида животных определил свой класс с общим базовым классом Pet. Для краткости ограничимся в описании каждого животного его кличкой и типовым излаваемым животным звуком с возможностью вывода на экран списка кличек и представления издаваемых ими звуков.
Программа:
Дата добавления: 2019-07-15; просмотров: 131; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!