В Delphi 2.0 був введений новий потужний тип даних - Variant. В основному його на значення полягало в підтримці автоматизації OLE (OLE Automation), де тип даних Variant використовується дуже широко. Фактично тип Variant мови Object Pascal є инкапсуляцией варіантів OLE. Як ми незабаром переконалися, реалізація в Delphi варіантів виявилася корисною і з точки зору інших аспектів программиро вання. Object Pascal є єдиним компільовані мовою, в якому для роботи з варіантами OLE введений спеціалізований тип даних, який надається як динамічний під час виконання програми і як статичний під час її компіляції.
У Delphi 3 для цієї ж мети був введений ще один новий тип даних - OleVariant, повністю ідентичний типу Variant, за винятком того, що він може містити лише ті типи, які сумісні з OLE. Далі в цьому розділі тип Variant і відмінності між типами даних OleVariant і Variant розглядається більш докладно.
Variant - динамічна зміна типу
Основне призначення типу Variant - надати можливість оголосити пере менную, тип якої невідомий на момент компіляції. Це означає, що настою щий тип такої змінної може змінюватися в процесі виконання программи.Напрімер, наведена нижче програма коректна і компілюватиметься і ви
виконуватися без помилок.
V: Variant; // V - змінна типу Variant
V: = 'Delphi is Great!'; // V містить рядок (тип string)
V: = 1; // V - ціле число (тип Integer)
V: = 123.34; // V - дійсне число (тип float)
V: = True; // V - логічне значення (тип boolean)
V: = CreateOleObject ( 'Word.Basic'); // V містить об'єкт OLE
Структура визначення даних типу Variant
Структура визначення даних типу Variant описана в модулі System і вигля
дит наступним чином:
TVarType = Word; PVarData = ^ TVarData;
case Integer of
0: (Reserved1: Word;
case Integer of
0: (Reserved2, Reserved3: Word;
case Integer of
varSmallInt: (VSmallInt: SmallInt);
varInteger: (VInteger: Integer);
varSingle: (VSingle: Single);
varDouble: (VDouble: Double);
varCurrency: (VCurrency: Currency);
varDate: (VDate: TDateTime);
varOleStr: (VOleStr: PWideChar);
varDispatch: (VDispatch: Pointer);
varError: (VError: LongWord);
varBoolean: (VBoolean: WordBool);
varUnknown: (VUnknown: Pointer);
varShortInt: (VShortInt: ShortInt);
varByte: (VByte: Byte);
varWord: (VWord: Word);
varLongWord: (VLongWord: LongWord);
varInt64: (VInt64: Int64);
varString: (VString: Pointer); varAny: (VAny: Pointer); varArray: (VArray: PVarArray); varByRef: (VPointer: Pointer);
1: (VLongs: array [0..2] of LongInt);
2: (VWords: array [0..6] of Word);
3: (VBytes: array [0..13] of Byte); Структура TVarData займає 16 байт пам'яті. Перших два байта цієї структури містять слово, значення якого визначає, на який саме тип даних сси лается варіант. Нижче наведені конкретні значення, відповідні відмінності ним типам даних, які можуть бути поміщені в поле VType записи TVarData. Наступні 6 байт записи не використовуються. Останні 8 байт містять або на стоять дані, або покажчик на дані, представлені цим варіантом. Чи не обходимо відзначити, що дана структура точно відповідає вимогам, що пред'являються до реалізації варіантів OLE.
varEmpty = $ 0000;
Як можна помітити з вищенаведеного коду, Variant не може містити посилання на дані типу Pointer або class.
З опису структури запису TVarData видно, що вона дійсно може містити в дані будь-якого типу. Слід відрізняти наведену вище запис TVarData від дійсних даних типу Variant. Хоча запис змінного складу і дані ти па Variant (варіант) зовні схожі за своїм призначенням, вони представляють дві з вершенно різні конструкції. Запис TVarData дозволяє зберігати дані різних типів в одній і тій же області пам'яті (подібно об'єднанням - union мови C / C ++). Більш детальна інформація по цій темі наведена далі в цій главі. Опера тор case в описі запису TVarData служить для визначення типів даних, які може представляти варіант. Так, якщо в поле VType міститься значення varInteger, то тільки чотири з восьми байтів даних записи будуть містити збережене змін ної ціле значення. Подібним чином, якщо в поле VType міститься значення var- Byte, тільки один з восьми байтів області даних буде використовуватися для зберігання значення.
Зверніть увагу, якщо VType містить значення varString, то вісім байтів даних в запису містять не реальну рядок, а лише покажчик на неї. Це дуже важливо розуміти, оскільки при роботі з варіантами можна отримати непосредст венний доступ до значень будь-якого поля, як показано в наведеному нижче прикладі.
Слід віддавати собі звіт в тому, що таке використання варіанту - небезпечна гра, так як при цьому, наприклад, можна легко зруйнувати покажчик на рядок або інший об'єкт з керованим часом життя. В результаті об'єкт стане недоступ ним для процесів "прибирання сміття", що призведе до витоку пам'яті (leaking memory) і втрати інших ресурсів програми. Більш детальна інформація про процеси "прибирання сміття" приведена в наступному розділі.