Имя: Пароль:
IT
 
C++: проблема возвращения значения при полиморфизме
,
0 Ненавижу 1С
 
гуру
28.09.11
11:19
Предположим мы хотим реализовать некую фабрику классов, строим абстрактное "ядро":
class AbstractObject
{
public:
   virtual void Test() =0
};

class AbstractFactory
{
public:
   virtual AbstractObject CreateObject() const =0;  //какой тип вернуть?
};
и тут же натыкаемся проблему какой тип должен возвращать метод
virtual AbstractObject CreateObject() const
Варианты:
1. Объект AbstractObject вернуть нельзя, ибо он содержит абстрактный метод Test(), но даже если сделать пустую реализацию {} у него, то полиморфизм теряется
2. Ссылку AbstractObject& вернуть нельзя, ибо в конкретной реализации это будет ссылка на временный объект, что запрещено компилятором
3. Константная ссылка const AbstractObject&. Но тут же накладывается условие на константность методов результата Test() const. Не всегда приемлемо.
4. Единственно приемлемый вариант указатель: AbstractObject*. Минус этого подхода состоит в том, что мы обязаны самостоятельно следить за уничтожением объектов.
5. Альтернативный вариант. Создать обертку
class WrapObject
{
private:
   AbstractObject* object;
public:
   WrapObject(AbstractObject* obj)
   {
       object = obj;
   }
   ~WrapObject()
   {
       delete object;
   }
   void Test() const
   {
       object->Test();
   }
};
Соответственно реализация
class AbstractFactory
{
public:
   virtual WrapObject CreateObject() const =0;
};

Прошу комментировать, возможно я сильно заблуждаюсь
1 Oftan_Idy
 
28.09.11
11:24
копай в сторону "чисто виртуальных" функций pure virtual func1().
Нужно сделать чисто виртуальный класс
2 Ненавижу 1С
 
гуру
28.09.11
11:25
(1) какой класс сделать чисто виртуальным?
3 dmpl
 
28.09.11
11:31
(0) А что компилятор пишет при попытке вернуть тип объект?
4 Ненавижу 1С
 
гуру
28.09.11
11:37
(3) пишет, что нельзя, ибо тип содержит абстрактный метод
если метод сделать неабстрактным, то ошибок нет, но тип "обрезается" и полиморфизма нет
5 Ненавижу 1С
 
гуру
28.09.11
11:39
все разобрался, я заново "открыл" умные указатели ))

class WrapObject
{
private:
   AbstractObject* object;
public:
   WrapObject(AbstractObject* obj)
   {
       object = obj;
   }
   ~WrapObject()
   {
       delete object;
   }
   AbstractObject* operator->()
   {
       return object;
   }
};
6 Кириллка
 
28.09.11
12:13
(6)Иди еще раз переоткрой, а то он у тебя вредный к использованию получился.
7 Кириллка
 
28.09.11
12:18
+6 Объяснить нужно почему вредный?
8 Ненавижу 1С
 
гуру
28.09.11
12:20
(6) да задача просто несколько другая, если б нужен был бы именно он, то взял бы готовый
9 fellow
 
28.09.11
12:26
(4) Для реализации полимормфизма класс не обязан быть абстрактным. Виртуальных функций достаточно.
10 Ненавижу 1С
 
гуру
28.09.11
12:27
(9) да, но полиморфизм теряется, если присваивать именно объекты
11 fellow
 
28.09.11
12:28
(10)Возвращайся ссылку на объект.
12 Ненавижу 1С
 
гуру
28.09.11
12:30
(11) посмотри внимательно (0), там описаны различные варианты и дальнейшее их развитие
13 Кириллка
 
28.09.11
12:38
Полиморфизм работает на указателях + виртуальность.
14 Ненавижу 1С
 
гуру
28.09.11
12:40
(13) на ссылках оно тоже работает, только ссылки ограниченны, как видим, в использовании
15 fellow
 
28.09.11
12:40
virtual void Test() {} решит твою проблему.
16 Кириллка
 
28.09.11
12:43
(14)ээ, создание объекта CreateObject в куче и возврат на него константной ссылки??
17 Кириллка
 
28.09.11
12:44
+16 ну и в догонку: спорить влом - указатели только.
18 Ненавижу 1С
 
гуру
28.09.11
12:45
(15) не решит, я писал почему
(17) здесь да, но надо следит за их уничтожением
19 Кириллка
 
28.09.11
12:48
(18)всегда указатели для работы полиморфизма.
20 fellow
 
28.09.11
12:51
class AbstractObject
{
public:
  virtual void Test() =0
};

class AbstractFactory
{
public:
  virtual AbstractObject& CreateObject() const =0;  
};
21 fellow
 
28.09.11
12:52
+ Возврат ссылки не обязательно означает возврат временного объекта.
22 Ненавижу 1С
 
гуру
28.09.11
12:55
(20) ты пробовал это компилировать?
23 Кириллка
 
28.09.11
12:55
(21)ты реализацию CreateObject покажи тогда.
24 fellow
 
28.09.11
12:55
AbstractObject& RealFactory::CreateObject()const
{
RealObject* probj = new RealObject;
return *probj;
}
25 fellow
 
28.09.11
12:57
(22) Да, компилируется. Стандарту С++ соответствует.
26 Кириллка
 
28.09.11
12:58
(24)горцев рождаем чтоли? :)
27 fellow
 
28.09.11
12:59
(26) Поясни свою мысль.
28 Ненавижу 1С
 
гуру
28.09.11
13:04
(27) кто его уничтожит то? пока вижу никто
29 fellow
 
28.09.11
13:06
(28) Когда ты вдоволь наиграешься с объектом, вызовешь  delete &pRealObj;
30 Ненавижу 1С
 
гуру
28.09.11
13:07
(29) спасибо, тогда лучше указатели
31 fellow
 
28.09.11
13:12
(30) На самом деле, разница невелика. В любом случае, если твоя фабрика создаёт полиморфные объекты, которые будут использоваться вне функции, вызвавшей фабрику, тебе нужно будет или самому заботиться о времени их жизни, или использовать умные указатели (например, shared_ptr из boost).
32 Кириллка
 
28.09.11
19:26
(27)ну мысль уже пояснили и тему раскрыли.

Все-таки полиморфизм, я думаю, ТС подразумевался в таком виде:

class A {}; // подразумеваем виртуальный деструктор
class B : public A {};

A* a = new B;
33 fellow
 
28.09.11
20:11
(32) ТС, я думаю, хотел определить обобщённую стратегию создания объектов достаточно произвольного вида и манипулирования ими, для чего ему и понадобились абстрактные классы фабрик и объектов. Поскольку классы абстрактные,  то создать объекты этих классов невозможно, им можно только наследовать. Это - часть формального определения системы, создаваемой ТС.
Полиморфизм возникает как естественное следствие различной реализации классов-потомков (реальных фабрик и объектов) при единой спецификации наследуемых  интерфейсов базовых (абстрактных в данном случае) классов. При этом, говоря вообще, без виртуальных функций получаем статический полиморфизм.
Ссылка обозначает объект, на который она ссылается, а следовательно имеет в этом отношении семантику указателя. Более того, их реализация и представляет собой указатель.

А вот кто такие "горцы", которых зачем-то кто-то собирается "рождать", мне не понятно :)
Программист всегда исправляет последнюю ошибку.