Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Fundamentals of Symbian C++/Class Types & Declarations/ru

From Wiki
Jump to: navigation, search
Article Metadata

Статья
Перевод:
hamishwillee
Последнее редактирование: SuperZANAC (14 Jul 2013)

Contents

Базовые типы

В Symbian C++ определены несколько фундаментальных типов, которые используются вместо "родных" встроенных в C++ типов, чтобы не зависеть от компиляторов. Они представлены как набор typedef'ов внутри файла e32def.h как показано ниже:

Typedef Type Описание
TInt signed int В общих случаях следует использовать простые TInt или TUint, для знаковых и беззнаковых 32-битных целых чисел соответственно, конечно, если только нет особой причины использовать 8 и 16-битные варианты.
TInt8 signed char
TInt16 short int
TInt32 long int
TUint unsigned int
TUint8 unsigned char
TUint16 unsigned short int
TUint32 unsigned long int
TInt64 long long Эти типы используют имеющуюся родную поддержку 64-битовых чисел.
TUint64 unsigned long long
TReal32 float

Использования чисел с плавающей точкой лучше избегать, если только они не играют важную роль в программе. Множество устройств на платформе Symbian не имеют аппаратной поддержки чисел с плавающей точкой. Как результат, работа с такими числами у них занимает в несколько раз больше времени, чем с числами целыми.
TReal64 double

Наиболее серьезные вычисления с плавающей точкой требуют двойной точности. Все стандартные математические функции (смотри класс Math) принимают аргументы с двойной точностью. Числа с одинарной точностью должны использоваться там, где важен размер кода и скорость исполнения, конечно, если ограничение их точности приемлемо.
TReal double
TAny void TAny* используется вместо void* для описания указателя на объект неизвестного типа. Стоит заметить, что void все же используется для указания того, что функция ничего не возвращает.

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

void TypicalFunction(TAny* aPointerParameter);

вместо эквивалентной записи:

void TypicalFunction(void* aPointerParameter);

Следующая функция не та же самая, потому что тип возвращаемого объекта - указатель на "что-то":

TAny* TypicalFunction(TAny* aPointerParameter);

TBool int Этот тип следует использовать для булевых переменных. По историческим причинам, в Symbian C++ переменные типа TBool могут быть равны int ETrue=1 или EFalse=0. Так как C++ интерпретирует все ненулевые значения как истину, не стоит производить прямых сравнений с ETrue.

Заметьте, что все эти типы начинаются с заглавной буквы T, которая означает "Type", и указывает на простые базовые типы. В добавление к вышеизложенному можно сказать, что простые классы начинаются с T, например как enum'ы:

enum TFruit {EApple, EOrange, EPear};

Всегда следует использовать базовые типы Symbian C++ вместо их родных аналогов (то есть, использовать TInt вместо int). Однако, есть одно исключение, как упоминалось выше - всегда используйте void если метод ничего не возвращает.

Типы Классов

Symbian C++ также определяет несколько типов классов, каждый из которого имеет разные характеристики, например, то, где объекты могут быть созданы (на куче или в стеке), и то, как они впоследствии будут уничтожены. Эти соглашения делают создание, использование и удаление объектов более простыми. При написании кода, требуемое поведение класса должно соответствовать характеристикам классов Symbian C++. Позже, пользователь незнакомого класса будет уверен в том, как создавать объект, использовать его и затем уничтожать его без непредусмотренных эффектов, таких как утечка памяти.

Когда Symbian C++ был только создан, у него был свой родной механизм обработки исключений (сейчас дополнительно поддерживается стандартная обработка исключений C++), которая называется "сброс" ("leaving"); cо сбросами тесно связаны использование "очистки стека" ("cleanup stack") и двухфазного построения ("two-phase construction") (эти концепции описаны в последующих секциях). Разнообразные типы классов выросли как следствие из этих трех механизмов.

T Классы

T классы являются простыми классами, которые ведут себя подобно встроенным типам C++. По этой причине у них такой же префикс как у типов, описанных в таблице выше.

Когда Symbian C++ только разрабатывался, деструктор объектов, расположенных в стеке, не вызывался при возникновении исключения. Префикс T использовался для выделения типов, которые безопасно объявлять в стеке, другими словами, классов, которые не содержат членов , требующих очистку деструктором. Как результат, T классы не имеют деструкторов. Однако, для Symbian начиная с версии 9.1 это не тот случай. Сейчас для T классов стало возможным иметь деструктор, который вызовется, когда объект "выйдет из поля зрения" (однако же деструктор не должен "сбрасывать" или выкидывать исключения). Более подробно это обсуждается в статье The Implications of Leaving in a Destructor (Последствия "сбросов" из деструкторов).

Локально созданные объекты T классов обычно размещаются в стеке, но они также могут быть созданы и на куче - в действительности, некоторые T классы всегда должны размещаться только на куче, так как в противном случае результирующий объект займет слишком много места в стеке. На практике, если что-то больше 256 байт, то оно не должно идти в стек (по умолчанию размер стека всего лишь 8 кб!)

Не смотря на то, чтокласс содержит простые данные, некоторые T классы могут иметь довольно сложные API, например, как класс лексического анализа TLex или базовые классы дескрипторов TDesC и TDes, о которых позже. В других случаях, T классы являются простыми C-подобными структурами состоящих только из public данных.

C Классы

C классы всегда распологаются на куче. В отличии от T классов, C классы содержат указатели на другие объекты, и имеют деструкторы для очистки этих переменных членов.

Для правильного управления памятью, C классы в конечном итоге должны наследоваться от класса CBase (описан в заголовочном файле Symbian C++ e32base.h). У этого класса есть 3 характеристики, которые наследуются каждым C классом:

  • Безопасное уничтожение: CBase имеет виртуальный деструктор, поэтому CBase-наследованный объект уничтожается должным образом удалением через указатель базового класса.
  • Обнуление при инициализации: CBase перегружает оператор new обнулением объекта когда он создается на куче. Это означает, что все данные членов класса, наследованного от CBase будут заполнены нулями при создании, поэтому нет нужды делать это явно в конструкторе.
  • Приватный конструктор копирования и операторы присваивания. CBase класс объявляет это для предотвращения случайного ошибочного использования операторов копирования.

На практике, C классам часто требуется вызывать код, который может отказать. Хорошим примером будет объект, производящий распределение памяти, что может отказать, если свободной памяти недостаточно. Ошибки такого вида обрабатываются так называемыми сбросами ("leave"), корые более детально обсуждаются в Leaves and the Cleanup Stack (Сбросы и очистка стека). Конструкторам запрещается "сбрасывать", так как это может вызвать утечку памяти. Чтобы этого избежать C классы используют идиому под названием двух-фазное построение ("two-phase construction"). Двух-фазное построение описано в Object Construction (Построение объектов).

R Классы

Префикс R классов указывает на то, что он содержит дескриптор ("handle") внешнего ресурса, например, дескриптор серверной сессии. R классы чаще всего маленькие и обычно не содержат других членов, кроме дескриптора ресурса.

В то время как C класс напрямую распределяет ресурсы (память, к примеру), R классы делают это косвенно. Например, для того, чтобы открыть файл, надо использовать метод RFile::Open(). Класс RFile самостоятельно не открывает файл и, следовательно, не использует ресурсы напрямую. Вместо этого, у него есть дескриптор на класс в файловом сервере, который напрямую и открывает файлы и использует ресурсы.

В отличии от C классов, эквивалентного класса RBase не существует (хотя множество R классов наследуются от RHandleBase - это особенно важно для ресурсов, к которым может понадобиться доступ из нескольких потоков или процессов). Типичный R класс имеет простой конструктор, а метод инициализации обычно назывется Open(), но иногда бывает Create() или Initialize(), который должен быть вызван после конструктора для настройки соответствующего класса и сохранения его дескриптора как член-переменную объекта R класса.

R классы могут быть либо членами других классов либо локальными переменными в стеке. Их возможно создавать на куче, но так делать не принято, так как сделать их безопасными для сбросов ("leave safe") станет сложнее (смотри Leaves and the Cleanup Stack). R объекты нужно делать безопасными для сбросов ("leave safe"), если они используются в функции, которая может сбросить ("leave"), с помощью очистки стека ("cleanup stack").

Также R класс должен иметь метод ,с помощью которого можно освобождать ресурсы (через дескриптор). Хотя, в теории, эту функцию очистки можно назвать как угодно, почти всегда ее принято называть Close(). Типичные ошибки при использовании R классов - это, например, забыть вызвать Close() или неверно предположить, что деструктор очищает принадлежащий объекту ресурс. (CleanupClosePushL() используется для очистки ресурса в результате возникновения исключения, смотри Leaves and the Cleanup Stack.)

M Классы

Префикс "M" произошел от mixin ("примесь"), и обозначает классы интерфейсов. Единственной формой множественного наследования, поощряемого в Symbian C++, являются включения нескольких M классов.

M класс - это абстрактный интерфейс, в котором объявлены чисто виртуальные функции и нет полей данных.

Как и в Java интерфейсах, обычно M класс должен иметь только чисто виртуальные функции. Однако, могут возникнуть случаи, когда более подходящими будут виртуальные функции со своей реализацией в интерфейсе. Хороший пример этого появляется, когда все наследуемые классы данного интерфейса должны иметь общее поведение по умолчанию. Добавление этой реализации в интерфейс снижает дублирование кода и головную боль. Конечно, на то, что эта реализация в интерфейсе может делать, накладываются некоторые ограничения, так как "примесные" классы не должны иметь полей данных.

Когда класс наследуется от класса CBase (или его потомков) и одного или нескольких M классов, класс CBase (или потомок) должен стоять первым, для правильной работы функций очистки стека. То есть:

class CCat : public CBase, public MDomesticAnimal

вместо

class CCat : public MDomesticAnimal, public CBase

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

Так как нельзя создать экземпляр M класса и они не содержат полей данных, M классам не нужны конструкторы.

Иногда на C класс ссылаются через указатель на его родительский M класс. В этом случае M классу требуется деструктор (более детально об этом в статье Leaves and the Cleanup Stack) .

Если у M класса нету виртуального деструктора, вместо него вы можете добавить чисто виртуальную функцию Release(). Что она значит, будет описано в его реализациях в классах-наследниках (в C классах, эта функция может просто вызывать “delete this”). Это делает интерфейс болле гибгим - класс реализации может быть основан на стеке или на куче, иметь счетчик ссылок, специальную очистку или что-либо еще. Это разумный подход, так как интерфейсный M класс не должен быть связан с деталями реализации классов, которые его наследую. Вызывать ваш метод очистки Release() или Close() не обязательно, но очень полезно. Прежде всего, он узнаваем и достаточно легко понять, что он делает. Но что более важно, он позволяет клиенту использовать функции CleanupReleasePushL() или CleanupClosePushL(), как описано здесь.

Статические Классы

Некоторые классы в Symbian C++ содержат только статические функции - экземпляр такого класса создать нельзя; вместо этого их функции должны вызываться через оператор "::". Например:

User::After(1000); // Приостановить текущий поток на 1000 мс.

Такие классы обычно предоставляют вспомогательный функционал, где функции собраны в классе для удобства, и должны использоваться так же, как и пространства имен ("namespace"). (Эти классы были созданы до того, как использование пространств имен было стандартизировано. Теперь Symbian C++ поддерживает пространства имен, и их использование предпочтительней использованию статических классов. Однако, не стоит использовать анонимные пространства имен, так как они склонны генерировать разные бинарники всякий раз, когда их компилируют - для анонимных пространств имен генерируются уникальные случайные имена.) По конвенции об именах, статические классы именуются без буквы-префикса. Например классы User, Math и Mem.



Licence icon cc-by-sa 3.0-88x31.png© 2010 Symbian Foundation Limited. This document is licensed under the Creative Commons Attribution-Share Alike 2.0 license. See http://creativecommons.org/licenses/by-sa/2.0/legalcode for the full terms of the license.
Note that this content was originally hosted on the Symbian Foundation developer wiki.

This page was last modified on 14 July 2013, at 17:47.
1054 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×