Как на с++ создать объект, если имя класса становится известным только на этапе выполнения (имя родительского класса известно и в процессе написания программы)? Это вообще возможно?
|
Как на с++ создать объект, если имя класса становится известным только на этапе выполнения (имя родительского класса известно и в процессе написания программы)? Это вообще возможно?
Посмотри паттерн "абстрактная фабрика". Если в новом классе не появляются новые публичные методы, то вполне может подойти.
Если не подойдет под твою задачу, то посмотри среди других порождающих паттернов.
На Вики это:
Абстрактная_фабрика_(шаблон_проектирования)
Порождающие шаблоны проектирования
Книжка: Приемы объектно-ориентированного проектирования. Паттерны проектирования
Абстрактная фабрика это конечно хорошо, но смотрим туже вики:
В этом примере фабрика прописывется в коде, а потом функции use передается ссылка на ту или иную фабрику.Код:int main() { ToyotaFactory toyotaFactory; FordFactory fordFactory; use (&toyotaFactory); use (&fordFactory); return 0; }
Например в Java делаем так:
String name = "имя класса"
Class classDefinition = null;
classDefinition = Class.forName("packagename." + name);
myClass c = (myClass) classDefinition.newInstance();
c.execute();
И при выполнении программы класс будет найден во время выполнения. Естественно в интерфейсе myClass описан метод execute и предполагается что все загруженые этим куском кода классы будут этот интерфейс поддреживать.
Можно еще так делать.
При этом после добавления нового типа его создание надо прописывать только в одной месте - в фабрике.
Код:#include <iostream> // интерфейс для всех создаваемых объектов class IObjectable { public: IObjectable(); virtual ~IObjectable() = 0; // interface section public: virtual void execute() = 0; }; IObjectable::IObjectable() {} IObjectable::~IObjectable() {} class ClassA : public IObjectable { public: virtual void execute() { std::cout << "This is ClassA execute()\n"; } }; class ClassB : public IObjectable { public: virtual void execute() { std::cout << "This is ClassB execute()\n"; } }; // фабрика class ObjectFactory { private: ObjectFactory(); public: static IObjectable * getObjectInstance(char * className); }; IObjectable * ObjectFactory::getObjectInstance(char * className) { if (0 == strcmp(className, "ClassA")) return new ClassA; if (0 == strcmp(className, "ClassB")) return new ClassB; return 0; } int main(int argc, char *argv[]) { std::cout << "Start\n"; IObjectable * myObject = 0; myObject = ObjectFactory::getObjectInstance("ClassA"); if (myObject) myObject->execute(); delete myObject; myObject = 0; myObject = ObjectFactory::getObjectInstance("ClassB"); if (myObject) myObject->execute(); delete myObject; myObject = 0; return 0; }
Последний раз редактировалось DiMomite; 02.10.2011 в 19:11.
maxx, все возможно. Иначе не было бы смысла в наследовании и полиморфизме.
Если у тебя в дочернем классе есть только переопределени(override) и нет замещений(типа, new) - смело объявляй переменную с типом родительского класса и на этапе исполнения присваивай ей экземпляр дочернего - все будет работать гуд.
Другой вопрос, если были замещения.
Как самый общий вариант - объявить переменную object и на этапе исполнения делать кастинг, но удобность этого варианта зависит от дальнейшего кода.
В общем случае, лучше применить интерфейс, и унаследоваться от него тоже.
Уточни задачу. Может чего придумаем
Последний раз редактировалось Hose; 03.10.2011 в 10:17.
Как я понял сложность как раз в создании дочернего элемента по имени класса в рантайме и состоит.
В джаве это возможно благодаря рефлексии. Коллеги говорят что в C# как в джаве нельзя. Про С++ тоже больше комментариев что нельзя.
Один говорит что как-то при помощи макросов можно, хотя у меня это вызывает сомнения - макросы на этапе компиляции разрешаются. Как освободится покажет, если это будет решением, напишу тут.
одно замечание, насколько я знаю обьявить в базовом классе деструктор чисто виртуальным - не есть гут.class IObjectable
{
public:
IObjectable();
virtual ~IObjectable() = 0;
// interface section
public:
virtual void execute() = 0;
};
далее. для явы требуемая функциональноать возможна в силу того что ява - интерпретатор.
т.е. модули могут компилироватся отдельно. и скажем модуль А, и не знает конкретное имя класса который он вызовет.
класслоадер этот класс разыщет.
а в с++ такую штуку легко симитировать используя динамические библиотеки. - но это уже ВНЕ стандарта с++.
индивидуальная субстанция разумной природы
Я чуть ниже предоставил пустую реализацию для этого деструктора. Объявление деструктора чисто виртуальным делает класс гарантированно абстрактным (подобного эффекта можно добиться если объявить конструктор protected, тут уже вопрос личных предпочтений). В данном конкретном случае это не обязательно, потому что в классе есть еще одна чисто виртуальная функция. Однако такая "метка", позволяет с первого взгляда определить что класс является абстрактным.
первое. абстрактный класс такого понятия в С++ стандарте нет. это вы с явой попутали - там есть.
далее.. небольшая проблема.
обьявив деструктор базового класса чисто виртуальным. вы вводите memory leak.
если вы удаляете обьект используя указатель на базовый класс. у вас происходит потеря памяти.
нет? я давно кодил в С++.
индивидуальная субстанция разумной природы
тут небольшая путаница.Объявление деструктора чисто виртуальным делает класс гарантированно абстрактным (подобного эффекта можно добиться если объявить конструктор protected, тут уже вопрос личных предпочтений).
конструктор protected, вовсе не гарантирует того что обьект этого типа не может быть создан.
индивидуальная субстанция разумной природы
DiMomite, я бы все же не стал искать общие методы, отталкивался бы от конкретной задачи.
В общем случае, в языке С++ нет и не может быть задач, с требованием создавать экземпляр по имени в рантайм. Есть задачи, когда это могло бы быть удобным, но прожить без этого можно.
С++ и удобство местами не совсем совместимы
Для любителей удобств надо как минимум С++/CLI пользовать, а существенно лучше, при возможности сразу в C# или VB.net уходить или в джаву - кто что любит
гля дя что понимать под удобством.
как по мне удобен скальпель. а кто то считает удобным картонный ножик.
индивидуальная субстанция разумной природы
Я под удобством понимаю быстроту и эффективность решения современных типовых задач.
В частности, к решению SaaS архитектур С++ приспособлен боком, с помощью доп.библиотек, тогда как для .net языков и джавы это типовые задачи.
Конечно, если требуется написать компилятор языка или ОС, подход должен быть индивидуальным, а в решении подавляющего большинства актуальных на сегодня задач гламурные языки вполне оправдывают себя
Социальные закладки