Nebula – подсистема Core
Автор: crionuke
Подсистема Core
Подсистема Core (название говорит само за себя) реализует базовые возможности движка Nebula3, а именно:
• Базовый класс RefCounter, реализующий механизм подсчета ссылок
• Система проверки типов (Runtime type information system или сокращенно RTTI)
• Шаблонный класс специальных укащателей (smart pointer) Ptr<>, который управлет объектами RefCounter
• Механизм фабрики, который позволяет создавать объекты С++ по строке, содержащей имя класса
• Объект центрального Сервера (central Server), который формирует основное окружение Nebula3.
Объектная модел Nebula3
Объектную модель Nebula3, реализует следующие новые особенности в довершение объектной модели C++:
• Управление временем жизни объектов с помощью механизма подсчета ссылок и специальных указателей (smart pointer)
• Создание объектов по строке с именем класса или по идентификатору (FourCC) класса.
• Система проверки типов (RTTI)
Создание нового класса Nebule3
Должен ли новый класс наследоваться от класса Core::RefCounted или быть обычным классом C++? Надеюсь следующие утверждения ответят на этот вопрос:
• Если класс будет использовать расширенную объектную модель Nebula3, подсчет ссылок или RTTI, и т.д., тогда он должен быть наследником класса Core::RefCounted
• Если новый класс является обычным небольшим вспомогательным классом, тогда не имеет смысла наследовать его от Core::RefCounted
Наследование от Core:RefCounted подразумевает некоторый ограничения:
• Объекты классов наследников RefCounted, никогда не должны создаваться непосредственно в локальном контексте C++, как стековый объект (stack object), потому что временем жизни таких объектов управляет сам C++ (такие объекты автоматически уничтожаются, когда текущий котекст C++ остановлен, а это нарушит механизм подсчета ссылок Nebula3)
• Классы наследники RefCouted должны иметь обычный конструктор
• Классы наследники RefCouted должны иметь виртуальный деструктор
Нормальный класс наследник Core::RecCounted похож на этот:
namespace MyNamespace { class MyClass : public Core::RefCounted { DeclareClass(MyClass); public: /// constructor MyClass( ); /// destructor virtual ~MyClass( ); ... }; RegisterClass( MyClass);
Обратите внимание на макрокоманду DeclareClass, обычный конструктор, виртуальный деструктор, и RegisterClass за пределами декларации класса. Макрокоманда DeclareClass добавляет в декларацию класса некторую специальную специфическую для Nebule3 информацию для RTTI и фабрики. DeclareClass снимает с программиста заботу по реализации объектной модели Nebula3, так что изменения объектной модели не влияет на существующие классы. Макрокоманда RegisterClass обязательна и регистрирует класс в фабрике объектов. Если вы точно знаете, что объекты этого класса никогда не будут создаваться по имени класса или FourCC коду, тогда макрокоманду RegisterClass можно опустить.
Реализация класса (.cc файл) должна содержать следующую специфичную для Nebula3 инфомрацию.
namespace MyNamespace { ImplementClass(MyNamespace::MyClass, 'MYCL', Core::RefCounted); }
Макрокоманда ImplementClass регистрирует класс в RTTI механизме, первый параметр описывает имя класс C++ (Примечание: имя пространства имен должно обязательно тут присутствовать). Второй параметр задает FourCC код для этого класса, он должен быть уникальным для всех классов, иначе вы получите ошибку при запуске приложения, Третий параметр это команды задает имя класс родителя. Это имя нужно для того, что бы RTTI механизм смог реконструировать дерево объектов.
Подсчет ссылок и специальные указатели
Nebula3 использует традиционные механизм подсчета ссылок для управления временем жизни объектов. Шаблонный класс для специальных указателей Ptr<> существует для того чтобы спрятать от программиста детали механизма подсчета ссылок. Всегда используйте специальные указатели для указателей на объекты классов наследников от RefCounted, за исключением тех мест в коде, где ты можешь быть уверен, что счечик ссылок на объект не изменится
Специальные указатели имеют целый ряд преимуществ над обычными указателями:
• Доступ к пустому указателю приводит сообщению об ошибки, которую легко будет отладить вместо непонятного сообщения об утечки памяти.
• Тебе никогда не придуется вызывать AddRef() или Release() в твоих объектах с подсчетом ссылок,
• Специальные указатели хорошо работают в классах контейнерах, массив специальных вместо массива обычных указателей исключает все типичные проблемы с управлением времением жизни, а именно теперь вам не нужно заботится об уничтожении объектов.
Так же есть некоторые недостатки о специальными указателями:
• Производительность: за копированием или назначением специальных указателей всегда следует вызов AddRef() и/или Release() у этих объектов.
• По-видемому мертвые объекты могут быть еще живыми: это происходит, когда последний клиент объекта отказался от его использования, т.е. счетчик ссылок стал равен нулю, после это объект может быть еще жив. Nebula3 известит вас об любых утечках RefCounter (т.е. об объектах, ктоторые существуют во время останоки приложения.
Создание объектов Nebula3
Объекты классов, которые наследованы от Core::RefCounter могут быть соданы тремя различными путями.
Напрямую через метод Create()
Ptr<MyClass> myObj = MyClass::Create();
Метод Create() добавляется в класс через макрокоамнду DeclareClass(), описанную ранее. На самом деле мтод Create() яавляется лишь оберткой над операторо new(). Фактически он является inline-методом с вызовом оператора new внутри.
Другой способ: создать Nebula3 объект по имени класса.
using namespace Core; Ptr<MyClass> myObj = (MyClass*) Factory::Instance( )->Create( "MyNamespace::MyClass");
Создание объекта по имени класса полезно, когда ты не знаешь класс объета на этапе компиляции.
И последний способ: создать объект по FourCC коду.
using namespace Core; using namespace Util; Ptr<MyClass> myObj = (MyClass*) Factory::Instance( )->Create( FourCC( 'MYCL'));
Это менее интуитивно понятный способ, но он часто работает быстрее, чем создание объекта по имени классса, потому что FourCC код занимает меньше места (4 байта) чем строка с именем класса.
19 мая 2008
Комментарии [5]