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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Связь класса с определённой структурой данных, Использование TypeList из loki ? 
:(
    Опции темы
eXtremal7
Дата 3.9.2009, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Предположим, есть набор объектов типа:
Код

class base {...};
class A : public base {...};
class B : public base {...};
class C : public base {,,,};


Задача состоит в том, чтобы была возможность доступа к определённой структуре данных(уникальной для A, B и C) во время выполнения. Для этого в базовый класс base можно добавить поле типа int index, создать массив структур, и получать нужную структуру по индексу. Однако при создании объектов A, B и C надо же как-то этот индекс определять то. Вот для этого и можно использовать список типов из библиотеки loki:

Код

typedef MakeTypelist<A, B, C>::Result AllTypes;


Тогда можно преобразовывать имя типа в индекс, но тогда как объявить массив структур, о котором говорилось выше? Разве что только так:

Код

//_objectDescription - статическая структура, которая должна быть отдельно
// описана для A, B и C
StructType AllStructures[Length<AllTypes>::value] = {
  TypeAt<AllTypes, 0>::Result::_objectDescription, 
  TypeAt<AllTypes, 1>::Result::_objectDescription,
  TypeAt<AllTypes, 2>::Result::_objectDescription
};


А конструкторы объектов будут выглядеть как-то так:

Код

A() : base(IndexOf<AllTypes, A>::value) {}


Решение вполне рабочее, но два момента совсем не нравится:
    Ручное указание всех элементов в структуре(TypeAt<AllTypes, 0>, TypeAt<AllTypes, 1> и.т.д.)
    Явное указание типа объекта в конструкторе(indexOf<AllTypes, A>)
Вот это хотелось бы как-то обойти, т.е. сделать так, чтобы список типов раскрывался автоматом, когда массив AllStructures объявляешь, а также чтоб в indexOf не надо было явно передавать тип - может как-нибудь можно использовать "this", ведь компилятору известен его тип..
PM MAIL   Вверх
mes
Дата 3.9.2009, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



посмотрите паттерн визитор


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


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

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



можно использовать специализацию классов вместо списков типов:

Код

template<class T>
class myTraits;


temlate<>
class myTraits<A>
{
public:
static StructType value;
};

template<>
StructType myTraits<A>::value = {...};


но, стоит задаться вопросом, зачем? ведь это:
Цитата(eXtremal7 @  3.9.2009,  10:44 Найти цитируемый пост)
Задача состоит в том, чтобы была возможность доступа к определённой структуре данных(уникальной для A, B и C) во время выполнения.
можно сделать с помощью статического члена класса A, B и С.  smile 
PM MAIL Skype GTalk   Вверх
eXtremal7
Дата 3.9.2009, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(Lazin @  3.9.2009,  11:18 Найти цитируемый пост)
можно сделать с помощью статического члена класса A, B и С.  smile  

И как я смогу по указателю базового класса к ним добраться интересно? smile Разве что объявлять виртуальную функцию в A, B и C. Проверить, является ли base* X указателем на A, B или C можно будет только dynamic_cast, а это всё неэффективно.

Была идея хранить непосредственно указатель на структуру в базовом классе вместо индекса.. тогда список типов не нужен:

Код

class base {
private:
  StructType *value;
}


но появляется ограничение - весь код с этими классами должен собираться как shared library(.dll/.so), в противном случае в каждом исполняемом модуле будет своя копия структур.. может быть так что объекты будут одинаковые, а значения value - разные, поэтому проверить принадлежность указателя base к производным классам простым сравнением value нельзя.


Цитата(mes @  3.9.2009,  11:01 Найти цитируемый пост)
посмотрите паттерн визитор 

А это что, можно подробнее ?
PM MAIL   Вверх
zim22
Дата 3.9.2009, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


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

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



Цитата(eXtremal7 @  3.9.2009,  11:42 Найти цитируемый пост)
А это что, можно подробнее ?

http://lmgtfy.com/?q=%D0%BF%D0%B0%D1%82%D1...%82%D0%BE%D1%80


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


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

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



поскольку StructType один и тот-же для A, B и С, то можно добавить виртуальный метод(защищенный), который будет возвращать указатель на эту структуру и вызываться он будет из базового класса, это очевидный вариант

можно еще ввести класс - посредник, между классом А..С и базовым классом - 
Код

class Base
{
protected:
    virtual StructType& getStruct() = 0;
public:
    void foo()
    {
        StructType& s = getStruct();
    }
};

template<class Derived>
class BaseProxy : public Base
{
protected:
    StructType& getStruct()
    {
        return static_cast<Derived*>(this)->metadata;
    }
};

class A : public BaseProxy<A>// вместо Base
{
    template<class D> 
    friend class BaseProxy;

    static StructType metadata;
public:
};

StructType A::metadata = {...};

тут, шаблон BaseProxy, знает тип своего потомка, и может извлечь какие-либо специфичные для A данные, благодаря этому, не нужно вручную определять метод getStruct для каждого потомка

Цитата(eXtremal7 @  3.9.2009,  11:42 Найти цитируемый пост)
И как я смогу по указателю базового класса к ним добраться интересно?

а как-бы тебе в этом помогли списки типов?

Добавлено @ 12:44
Цитата(eXtremal7 @  3.9.2009,  11:42 Найти цитируемый пост)
Разве что объявлять виртуальную функцию в A, B и C.
кстати, твой первоначальный пример, как раз и является кривой эмуляцией вызова вирт. ф-ии, по сути, не по форме


Это сообщение отредактировал(а) Lazin - 3.9.2009, 12:46
PM MAIL Skype GTalk   Вверх
Lazin
Дата 3.9.2009, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

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



Цитата(Lazin @  3.9.2009,  12:43 Найти цитируемый пост)
тут, шаблон BaseProxy, знает тип своего потомка, и может извлечь какие-либо специфичные для A данные, благодаря этому, не нужно вручную определять метод getStruct для каждого потомка

в принципе, это можно сделать еще проще, и более обобщенно:
Код

class Base
{
protected:
    virtual StructType& getStruct() = 0;
public:
    void foo()
    {
        StructType& s = getStruct();
    }
};


struct proxy_all_access
{
    template<class T>
    static StructType& getMetadata(T&)
    {
        return T::metadata;
    }
};

template<class Derived>
class BaseProxy : public Base
{
protected:
    StructType& getStruct()
    {
        return proxy_all_access::getMetadata(static_cast<Derived&>(*this));
    }
};

class A : public BaseProxy<A>// вместо Base
{
    friend proxy_all_access;

    static StructType metadata;
public:
};

StructType A::metadata = {...};

с помощью структуры proxy_all_access, можно не только ссылку на статический член класса - потомка возвращать, а вообще, делать с потомком все что душе угодно, для этого нужно добавить соотв. методы в структуру.
еще один плюс, тому, кто реализует класс - потомок, достаточно написать friend proxy_all_access, вместо template<class T> friend ...; это лучше читается
PM MAIL Skype GTalk   Вверх
eXtremal7
Дата 3.9.2009, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(Lazin @  3.9.2009,  12:43 Найти цитируемый пост)
кстати, твой первоначальный пример, как раз и является кривой эмуляцией вызова вирт. ф-ии, по сути, не по форме

Почему же кривой то, разве прочитать индекс из объекта будет не быстрее чем вызов виртуальной функции ? А есть сравнить производительность dynamic_cast со сравнением индекса: 
Код

if (base->ID == IndexOf<AllTypes, A>) {...}

Списки типов нужны чтобы сопоставить индекс каждому типу, это удобнее чем enum отдельный объявлять для этого.

Цитата(Lazin @  3.9.2009,  12:43 Найти цитируемый пост)
поскольку StructType один и тот-же для A, B и С, то можно добавить виртуальный метод(защищенный), который будет возвращать указатель на эту структуру и вызываться он будет из базового класса, это очевидный вариант

Если предполагается расширяемость, то это единственный путь, а вот если набор объектов жестко зафиксирован, почему бы и не оптимизировать доступ к структуре и проверку типов ?
PM MAIL   Вверх
Lazin
Дата 3.9.2009, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

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



Цитата(eXtremal7 @  3.9.2009,  13:16 Найти цитируемый пост)
Почему же кривой то, разве прочитать индекс из объекта будет не быстрее чем вызов виртуальной функции ? А есть сравнить производительность dynamic_cast со сравнением индекса
прочитать индекс из объекта не намного быстрее, чем получить адрес вирт. ф-ии из VMT объекта, разница в один уровень косвенности при обращении к данным
в любом случае, это преждевременная оптимизация, к тому-же очень сомнительная smile

Добавлено через 4 минуты и 21 секунду
Цитата(eXtremal7 @  3.9.2009,  13:16 Найти цитируемый пост)
А есть сравнить производительность dynamic_cast со сравнением индекса: 

Код

if (base->ID == IndexOf<AllTypes, A>) {...}

каждый программист, рано или поздно пытается написать свою "быструю" замену dynamic_cast? smile
если правильно спроектировать программу,то dynamic_cast не нужен
PM MAIL Skype GTalk   Вверх
eXtremal7
Дата 4.9.2009, 11:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(Lazin @  3.9.2009,  13:31 Найти цитируемый пост)
если правильно спроектировать программу,то dynamic_cast не нужен

Далеко не всегда известен тип данных во время компиляции.. но если известен, то конечно dynamic_cast не нужен.
А там где нужен обычно и делают свои ускоренные реализации.
PM MAIL   Вверх
mes
Дата 4.9.2009, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(eXtremal7 @  4.9.2009,  10:20 Найти цитируемый пост)
Далеко не всегда известен тип данных во время компиляции.. но если известен, то конечно dynamic_cast не нужен.
А там где нужен обычно и делают свои ускоренные реализации. 

Lazin имел в виду, что dynamic_cast не используется не потому, что известен реальный тип объекта, а потому что есть другие способы реализации нужного взаимодействия с объектом,
и они не есть ускоренные реализации dynamic_casta.



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


Новичок



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

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



Цитата(mes @  4.9.2009,  12:28 Найти цитируемый пост)
Lazin имел в виду, что dynamic_cast не используется не потому, что известен реальный тип объекта, а потому что есть другие способы реализации нужного взаимодействия с объектом,и они не есть ускоренные реализации dynamic_casta.

А я говорю, что не всегда можно так организовать взаимодействие с объектом, что dynamic_cast будет не нужен, могу привести пару примеров: llvm.org и их набор шаблонов cast<>, dyn_cast<>, isa<>, ну а также Qt и их qobject_cast<> - всё это является ускоренными аналогами dynamic_cast-а и активно используется в этих проектах.
PM MAIL   Вверх
hente
Дата 7.9.2009, 14:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 116
Регистрация: 20.3.2009
Где: Томск

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



гы....задача таже самая тока под Linux. Кропотливое но элементарное решение как было сказано выше с помощью паттерна  визитор.
Реализовав раз достаточно легко переносится на  другой проект...Где то год назад(даже не зная слова паттерн) сам придумывал мучился кое-как сделал, щас на это дело ушло пару часов, за одно и старую библиотеку переделалsmile smile 
Вообще хочу сказать что паттерны милое дело если грамотно делать то переносимость 100%я (Win<->Linux, без Qt), а времени скока экономит так ваще молчу....

К стате советую книгу "Приемы объектно орентированного проектирования" Э.Гамма,Р.Хелм,Р.Джонсон,Д.Влиссилес. smile 

Это сообщение отредактировал(а) hente - 7.9.2009, 14:30
--------------------
  долой быдло кодеров!!!
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

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

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

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

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


 




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


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

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