Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Полиморфизм + шаблон 
:(
    Опции темы
ZeusAtVingrad
Дата 19.4.2013, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 82
Регистрация: 12.4.2006

Репутация: нет
Всего: нет



Можно ли в C++ описать в базовом классе интерфейс без указания типа (т.е. шаблон?), а в базовых переопределить их - и так, чтобы это получилось полиморфно?

Подробнее:
Есть такой код:
Код

#include <iostream>

template<typename C>
class    A
{
    public:
    virtual    C    operator()    ()    = 0;
    virtual    void    operator()    (C)    = 0;
};

class    B: public A<long>
{
    public:
    virtual    long    operator()    ()        { return 321; };
    virtual    void    operator()    (long _value)    { std::cout << _value << std::endl; };
};

int
main ()
{
    B    b;
    A<long>&    a = b;
    std::cout << a() << std::endl;
    a(123);
    return 0;
};

Он комплириуется и "работает" (если не считать, что это просто "пробник" и ничего толкового он не делает).

Проблема в том, что мне нужно описать класс (или функцию класса) о котором на момент компиляции известно только, что в нём есть функция getA, которая вернёт ссылку (указатель или может вообще объект) типа А.
Код

class Test
{
...
virtual A& getA() = 0;
...
};

class Test1: public Test
{
...
virtual B& getA {}
...
}


Но А - это же шаблон. Его же нельзя просто так написать как возвращаемый функцией результат.
А какой именно тип вернёт getA будет зависеть от того экземпляр какого класса-наследника Test вызовут:
Ну и естественно "пользователь" этого ничего знать не должен. Ему дали указатель (ссылку) на Test, он вызывает getA.... и вот тут тонкость: ВЫЗЫВАЮЩИЙ код - ЗНАЕТ какой именно тип вернёт getA.
Но как это расписать в виде классов-шаблонов - ума не приложу.

Спасибо.

Это сообщение отредактировал(а) ZeusAtVingrad - 19.4.2013, 15:09
PM MAIL   Вверх
mes
Дата 19.4.2013, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



 smile много воды..

в принципе см. boost::any или variant.. 




--------------------
PM MAIL WWW   Вверх
borisbn
Дата 19.4.2013, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Интересно... у меня де-жа-вю или это ты на куче форумов одно и то же спрашиваешь ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
volatile
Дата 19.4.2013, 23:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(ZeusAtVingrad @  19.4.2013,  15:08 Найти цитируемый пост)
virtual A& getA() = 0;
...
};

class Test1: public Test
{
...
virtual B& getA {}

Функции отличаюцца только возвращаемым типом. Это в С++ недопустимо.
В остальном да, много воды...

PM MAIL   Вверх
mes
Дата 20.4.2013, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(volatile @  19.4.2013,  22:53 Найти цитируемый пост)
Функции отличаюцца только возвращаемым типом. Это в С++ недопустимо.

иногда все ж допустимы  smile 

Код

struct A {};
struct B : A {};
struct C : A {};

struct IGet

   virtual A& get() =0;
};

struct Get1 : IGet
{
   B b;
   virtual B& get() { return b; }
};

struct Get2 : IGet
{
   C c;
   virtual C& get() { return c; }
};



--------------------
PM MAIL WWW   Вверх
ZeusAtVingrad
Дата 20.4.2013, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 82
Регистрация: 12.4.2006

Репутация: нет
Всего: нет



1. Я понимаю, что много воды, но как-то трудно сформулировать...
Если просто словами, то - надо сделать базовый класс (шаблонизированный?) в котором тип ВОЗВРАЩАЕМОГО функцией значения будут "знать" только наследники и только тот, кто вызывает этого наследника.
Опять-таки, вызывающий код НЕ ЗНАЕТ какого именно наследника он вызывает (т.е. у него есть указатель или ссылка только на базовый класс и объявление класса наследника у него нет - ну типа полиморфизм), но при этом он всё-таки ЗНАЕТ, ЧТО именно ему вернут.
Он не знает КТО вернёт, но знает ЧТО вернут.

2. Знаю, что возвращаемое значение не входит в сигнатуру функции. Код который я привёл это как бы семантический пример. Понятно, что это не рабочий C++ код.

3. Знаю, что такого рода дела можно решать через всяческого рода any (boost::any например).
Но во-первых не хочется для небольшого проекта тянуть зависимость от boost, во-вторых подозреваю, что any_cast'ы всякие могут работать довольно медленно. А есть желание получить максимально быстрый код. Поэтому - статические проверки типов и/или приведение указателей по линии наследования. Но не проверка и приведение какого-то void* к любому типу.

4. На http://stackoverflow.com не мой вопрос.
PM MAIL   Вверх
mes
Дата 20.4.2013, 10:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(ZeusAtVingrad @  20.4.2013,  08:58 Найти цитируемый пост)
Он не знает КТО вернёт, но знает ЧТО вернут.

boost:any

Цитата(ZeusAtVingrad @  20.4.2013,  08:58 Найти цитируемый пост)
Но во-первых не хочется для небольшого проекта тянуть зависимость от boost, во-вторых подозреваю, что any_cast'ы всякие могут работать довольно медленно. А есть желание получить максимально быстрый код. 

тянуть не обязательно, можно быстренько написать свой аналог..  any это всего лишь концептуальная обертка над void*, позволяюшая легко хранить и копировать объект.. 

Цитата(ZeusAtVingrad @  20.4.2013,  08:58 Найти цитируемый пост)
что any_cast'ы всякие могут работать довольно медленно.

если проверка на валидность каста не нужна (не такое уж и длительное, сравнение например по type_id), то подойдет обычный static_cast.

Цитата(ZeusAtVingrad @  20.4.2013,  08:58 Найти цитируемый пост)
Но не проверка и приведение какого-то void* к любому типу.

так это база любого преобразования в с++  smile 



--------------------
PM MAIL WWW   Вверх
volatile
Дата 20.4.2013, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(mes @  20.4.2013,  09:40 Найти цитируемый пост)
иногда все ж допустимы   

mes, cенкс. хмм.. действительно...
Переобъявить возвращаемый тип как ссылку или указатель на наследника, оказываецца можно...
Но от необходимости каста мы, все равно, никуда не денемся.
Код

IGet * n = new Get2;
C & c = /*здесь нужен каст*/ n->get (); // точно также, как если бы мы тращиционно объявили C::get () возвращающий A&


Добавлено через 1 минуту и 53 секунды
Вообще, кастовать, а следовательно брать на себя всю работу по слежению за полиморфными типами.  smile  Упаси боже...
"кабаки да бабы доведут до цугундера" (с)... smile 

PM MAIL   Вверх
mes
Дата 21.4.2013, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(volatile @  20.4.2013,  22:08 Найти цитируемый пост)
Вообще, кастовать, а следовательно брать на себя всю работу по слежению за полиморфными типами

не следовательно.. smile  если вход-выход (для кастования)  "синхронизирован", как вероятно и в нашем случае, то зачастую разгрузить шаблоном, как например это делает any..

Добавлено через 2 минуты и 45 секунд
Цитата(volatile @  20.4.2013,  22:08 Найти цитируемый пост)
 точно также, как если бы мы тращиционно объявили C::get () возвращающий A&

не важно как объявили в наследниках, важно то с чем работаем..  а IGet возвращает A&..

Добавлено через 4 минуты и 6 секунд
чуть позже напишу пример )


Это сообщение отредактировал(а) mes - 21.4.2013, 12:18


--------------------
PM MAIL WWW   Вверх
mes
Дата 21.4.2013, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(mes @  21.4.2013,  11:18 Найти цитируемый пост)
чуть позже напишу пример )

http://codepad.org/legyGq8B

Код

#include <iostream>

struct iface 
{
  virtual ~iface() {}

  virtual iface * clone() const =0; 
  virtual void const* get_value_ptr() const =0;
  virtual std::string get_impl_name() const =0; 
};


template<typename T>
struct concrete
{
  concrete(iface *p) : _iface(p) {}
  concrete(concrete const& rhs) : _iface(rhs._iface->clone()) {}
 ~concrete() { delete _iface; }

  T get_value() { return *static_cast<T const*>(_iface->get_value_ptr()); }   
  std::string get_impl_name() const { return _iface->get_impl_name(); }
 
private: 
  iface * _iface;
};

template<typename T>
struct implA : iface 
{
  implA(T const& data) : _data(data) {}

  implA * clone() const { return new implA(*this); }
  void const* get_value_ptr() const { return &_data; }
  std::string get_impl_name() const { return "implA"; }
 
  T  _data;
};

template<typename T>
struct implB : iface 
{
  implB(T const& data) : _data(data) {}

  implB * clone() const { return new implB(*this); }
  void const* get_value_ptr() const { return &_data; }
  std::string get_impl_name() const { return "implB"; } 
  T  _data;
};

template<typename T>
concrete<T> create_concrete(T const& value, int impl_type=0) 

  return impl_type ==0 
     ? concrete<T>(new implA<T>(value))
     : concrete<T>(new implB<T>(value));
}

int main()
{
  for(int i=0; i<10; ++i)
  {
     concrete<int> a = create_concrete(i, rand() % 2);

     std::cout << a.get_impl_name() << " : " << a.get_value() << std::endl;
  }
}


Цитата

implB : 0
implA : 1
implB : 2
implB : 3
implB : 4
implB : 5
implA : 6
implA : 7
implB : 8
implB : 9


Это сообщение отредактировал(а) mes - 21.4.2013, 19:24


--------------------
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0689 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.