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

Методы класса

С указателем на класс тесно связано понятие особого типа методов – методов класса. Такие методы можно вызвать без создания объекта через имя класса, в котором они описаны. Хотя их можно вызывать и как обычные методы, через имя объекта. Перед описанием методов класса нужно поставить зарезервированное слово class.

Например:

Interface Type TMyObject = class(TObject) public class function GetSize: string; ... End;

Implementation Procedure Test; Var MyObject: TMyObject; AString: string; begin //вызываем метод класса GetSize через имя класса //без создания экземпляра объекта AString := TMyObject.GetSize; //создаем экземпляр объекта MyObject := TMyObject.Create; //вызываем метод класса GetSize как обычный метод AString := MyObject.GetSize; ... end;

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

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

class function ClassName: ShortString;

- возвращает имя класса;

class function ClassNameIs(const Name: string): boolean;

- возвращает true, если имя класса равно заданному;

class function ClassParent: TClass;

- возвращает указатель на родительский класс;

class function ClassInfo: pointer;

- возвращает указатель на структуру с дополнительными данными об опубликованных методах и свойствах;

class function InstanceSize: longint;

- возвращает размер экземпляра класса;

class function UnheritsFrom(AClass: TClass): boolean;

- возвращает true, если данный класс наследует от заданного;

class function MethodAdress(const name: ShortString): pointer;

- возвращает адрес метода по его имени (только для опубликованных методов);

class function MethodName(Adress: Pointer): ShortString;

- возвращает имя метода по его адресу (только для опубликованных методов);

Рассмотрим пример:

Interface Type TMyObject = class ... end;

TMyObjClass = class of TObject;

Implementation Procedure Test; var AMyObjRef: TMyObjClass; S: string; begin AMyObjRef := TObject; S := AMyObjRef.ClassName; //в результате S = ‘TObject’ AMyObjRef := TMyObject; S:=AMyObjRef.ClassName; //в результате S = ‘TMyObject’ end.

В этом примере с помощью метода класса TObject.ClassName получается имя реального класса, на который указывает указатель AMyObjRef.

    1. Статические элементы класса в С++

Механизм указателей на класс в Object Pascal позволяет рассматривать класс как некий объект, с которым можно работать – вызывать методы класса, создавать экземпляры объектов класса. В языке С++ нет специального типа «указатель на класс», тем не менее имеется возможность определять методы, вызываемые через имя класса и данные, общие для всех экземпляров одного класса. Это достигается за счет использования статических элементов класса.

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

class CMyClass { ... public: int UnStaticVar; //обычное поле static int StaticVar; //статическое поле void SomeFunction(void); //обычная функция static void SomeStaticFunction(); //статическая функция };

Такие элементы класса называют статическими - не следует путать со статическим перекрытием методов.

Доступ к статическим элементам класса может выполняться без создания экземпляра класса через имя класса:

int i = CMyClass::StaticVar; CMyClass::SomeStaticFunstion();

Также можно обращаться к статическим элементам класса как к обычным, через имя объекта или указатель на объект:

CMyClass c; c.SomeStaticFunction();

но конкретный экземпляр объекта при этом не принимается во внимание.

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

class CMyClass { private ... int Data; //не статическое поле static int StaticData; //статическое поле public: static int GetData(CMyClass * ptr); //статическая функция };

int CMyClass:: GetData(CMyClass * ptr) { //return Data+StaticData; //ошибка, поскольку нет указания //экземпляра класса для нестатического поля данных

return ptr->Data+StaticData; //указали конкретный объект //для статического поля указывать ничего не надо }

Статические функции-элементы не могут быть виртуальными функциями. Недопустимо объявлять статические и не статические функции-элементы с одинаковым именем и типами аргументов.

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

Статическое поле глобального класса определяется и инициализируется подобно обычным глобальным переменным. Причем сделать это можно только на уровне файла:

class CMyClass { private ... static int StaticData; //объявление статического поля – //память не распределяется public: static int GetDataStatic(void); //статическая функция int GetData (void); //не статическая функция };

int CMyClass::StaticVar = 10; //определение статического поля – //память распределяется и выполняется инициализация //определение не может быть вложено в какую-либо функцию и т.п.

int CMyClass:: GetDataStatic(void) { return StaticData; //статическая функция работает //со статическим полем данных }

int CMyClass:: GetData(void) { return StaticData; //обычная функция работает со //статическим полем данных – для всех экземпляров //класса это поле будет общим. }

Статические элементы класса используются, чтобы организовать данные, общие для всех объектов одного класс, и обеспечить удобный доступ к ним. Это могут быть такие данные, как число созданных экземпляров класса, ссылки на совместно используемые ресурсы и т.п. Использование статических элементов класса позволяет:

  • уменьшить число глобальных имен;

  • сделать очевидным то, что статическая переменная логически принадлежит определенному классу;

  • выполнять контроль над доступом к данным.

    1. С++ Шаблоны

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

Рассмотрим для примера функции поиска минимального из двух чисел разных типов. Такие функции могут быть описаны так:

//минимум для целых чисел int int Min( int a, int b) { return (a < b) ? a : b; };

//минимум для вещественных чисел double Min(double a, double b) { return (a < b) ? a : b; };

//минимум для символьного типа char Min(char a, char b) { return (a < b) ? a : b; };

Видно, что действия функций одинаковы, и все различие состоит в типе данных, с которыми они работают.

С помощью механизма шаблонов можно создать для них единый шаблон, который будет определен как:

template <class T> T Min(T a, T b) { return (a < b) ? a : b; };

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

Формат определения шаблонов классов и функций следующий:

template < [typelist] [, [ arglist ]] > declaration

где typelist – список разделенных запятой имен типов, которые будут использоваться в определении, arglist – список аргументов, declaration – объявление функции или класса – как обычных.

Таким образом, шаблоны функции или класса, называемые также параметризованными функциями и классами, представляют собой определение функции или класса, где один или несколько типов данных и значений аргументов объявлены как параметры. Определяя для этих параметров конкретные значения типов и величин, можно породить соответствующие функцию или класс, работающие с данными этих типов и имеющих установленные значения аргументов. С помощью значений аргументов можно, например, определить число элементов массива. Функции или классы, для которых задано значение параметров, называют инстацированными (наполненными или конкретизированными).

Пример создания и использования шаблона класса:

//параметризованный класс: template <class T, int i> class CTestClass //параметры – тип T и аргумент i { T arr[i]; public: void fin(int,T); T fout(int); };

//методы параметризованного класса также являются //параметризованными: template <class T, int i> T CTestClass<T,i>::fout(int i) { return arr[i]; };

template <class T, int i> void CTestClass<T,i>::fin(int i, T t) { arr[i] = t; };

Для инстацирования и создания экземпляра класса:

CTestClass<double, 5> ClassInst; //массив из пяти //вещественных чисел CTestClass<int, 3> ClassInst1; //массив из трех целых чисел

Использование объектов инстацированного класса ничем не отличается от работы с объектами обычных классов:

double a = 2.1, b; ClassInst.fin(1,a); ClassInst1.fin(1,a); b = ClassInst.fout(1); b = ClassInst1.fout(1);

Используя механизм шаблонов С++, легко создавать классы контейнеров, которые будут работать с широким кругом типов данных – как встроенных в язык, так и создаваемых программистом. Подобные контейнеры, реализующие массивы, списки и т.п. входят в состав многих библиотек С++.