LINUX.ORG.RU

Уникальный ID для класса.

 ,


1

3

Приветствую.

Вот какая фигня. Есть интерфейс, например

struct A {
    virtual ~A() { }
    virtual void somecall( ) = 0;
};
и есть несколько его релизаций, которые хранятся в мапе. в коде получение определенного объекта выглядит как-то так
class B: public A {} 
.....

mumap.getinst<B>( ).somecall( );

вызов getinst находит в мапе объект, приводит его к требуемому классу (static_cast) и возвращает ссылку нужного типа. колючем в мапе сейчас обертка над std::type_info, что не очень хорошо, поскольку можно сделать -fno-rtti и typeid будет недоступен.

Вопрос в том, как бы так сгенерить для каждого такого класса-наследника от A уникальный id и пользовать его в качестве ключа.

рассматриваю пока варианты:

- некое имя, которое прописывать к каждому классу (плохо)
- хеш от имени файла (макрос __FILE__). Да, каждый наследник реализован в отдельном. Не переносимо (?)
- случайное число, сгенеряченое при старте и лежащее в статическом члене + проверка на то, что такое уже, возможно попадалось и перегенерячивание заново при заполнении мапы. (хм, даже не знаю).

какие есть еще варианты?

какие есть еще варианты?

Статическое поле данных в каждом классе (хоть один байт), адрес которого автоматически будет уникальным и может служить ключём.

xaizek ★★★★★ ()

Тебе нужен именно RTTI и ты хочешь нагородить его костыльный аналог. Может лучше просто не отключать штатный функционал?

Кстати, возможно весь твой код может заменить dynamic_cast, ведь по сути дела именно его ты эмулируешь.

KivApple ★★★★★ ()

Вопрос в том, как бы так сгенерить для каждого такого класса-наследника от A уникальный id и пользовать его в качестве ключа.

А зачем, какая задача решается?

shty ★★★★★ ()
Ответ на: комментарий от KivApple

Кстати, возможно весь твой код может заменить dynamic_cast

если честно не понял мысль.

seryoga ()
Ответ на: комментарий от shty

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

seryoga ()
Ответ на: комментарий от vertexua

в какую сторону посмотреть? Примеры мож какие посоветуешь, доки?

Пока остановился на варианте xaizek. не нужно много переделывать, только пару строчек.

seryoga ()

В современных плюсах есть любопытный финт ушами

template <typename Singleton>
Singleton& singleton() {
  static Singleton singleton;
  return singleton;
}

это замечательный подарок комитета стандартизации всем программистам. Порядок разрушения не гарантируется, зато потокобезопасно.

В твоём случае, в шаблон нужно добавить dummy-параметр, например enum class с идентификатором и/или несколько перегруженных версий функции, чтобы можно было конструировать разные объекты одного типа.

Единственное «но», так это статический storage class и выбор версий только в компайл-тайме.

Macil ★★★★★ ()
Ответ на: комментарий от vertexua

о, а вот и вывихнутые подтянулись

anonymous ()
Ответ на: комментарий от Macil

Порядок разрушения не гарантируется

3.6.3 Termination [basic.start.term], 1:

... If an object is initialized statically, the object is destroyed in the
same order as if the object was dynamically initialized. ...
Т.е. порядок разрушения обратен порядку инициализации, как обычно (1, 2).

xaizek ★★★★★ ()
Ответ на: комментарий от Macil

Порядок разрушения не гарантируется

Это называется «слышал звон» (с) и нафантазировал сколько смог. А слышал ты наверняка про статичные члены класса у шаблонов, а не переменные. Во-вторых порядок разрушения гарантируется - он всегда обратен инициализации.

anonymous ()

Еще один извращенный вариант: парсить выхлоп __PRETTY_FUNCTION__ на предмет вычленения имени класса и считать от получившегося хеш (все это реально сделать в compile time, правда полгода назад gcc валился в ICE на выражении *__func__).

m0rph ★★★★★ ()
Последнее исправление: m0rph (всего исправлений: 1)
Ответ на: комментарий от jtootf

Он просто конкретную задачу решает и на краю создания эпичного велосипеда, в котором замешаны RTTI, type_index, какие-то статические поля сугубо для уникальной идентификации или еще что-то что тут посоветуют умники. Я могу посоветовать только два адекватных метода - ручное связывание без всего этого бреда и IoC

Городить весь ад c RTTI можно порекомендовать если задача учебная

vertexua ★★★★☆ ()
Последнее исправление: vertexua (всего исправлений: 1)
Ответ на: комментарий от vertexua

Городить весь ад c RTTI

Поэтому надо порекомендовать хиподермик, который суть тоже ад RTTI, обмазанный бустом. fuck logic =)))

anonymous ()
Ответ на: комментарий от anonymous

Именно нужно порекомендовать хиподермик, чтобы не городить самому. Так же как можно порекомендовать компилятор чтобы не писать бинари самому в hex редакторе.

vertexua ★★★★☆ ()

случайное число, сгенеряченое при старте и лежащее в статическом члене + проверка на то, что такое уже, возможно попадалось и перегенерячивание заново при заполнении мапы. (хм, даже не знаю).

Это плохое решение и тебе нужен dynamic_cast или даже простой полиморфизм, но на будущее: такое сгенеряченое число называется GUID/UUID.

E ★★★ ()

Давайте копнем выше. Насколько я понял, Вы хотите сделать контейнер для разных типов и чтобы сложить их вместе - придумали интерфейс. Но поскольку интерфейс не универсален для всех реализаций, то при вытаскивании элемента Вам нужно кастить в его старый тип. Я правильно понял то, что Вы хотите?

В общем если да, то подобное уже проходил. Идея не очень хорошая и лучше от нее уйти. Кастить от наследника с базовому - хорошо. Кастить от базового к наследнику - плохо, проблемы начинаются при множественном наследовании, причем очень большие. Там получается что указатель на объект базового не всегда равен указателю на объект производного. Соответственно помимо типа объекта вместо указателя на базовый класс необходимо хранить void* на объект производного. Соответственно интерфейс не нужен сразу становится. Эта конструкция получается громоздкой и некрасивой, в общем если есть возможность от нее уйти, следуйте моему опыту :)

Burns ()

Всем спасибо за подсказки.

vertexua спасибо за ссылку, тема интересная. Проект у меня действительно длясебяйный и значит от части учебный. в учебных люблю велосипеды делать. К томуж часть из того что в hypodermiс есть я уже навелосипедил, можно велосипедить дальше:))

seryoga ()
Ответ на: комментарий от Burns

Кастить от базового к наследнику - плохо

чего бы это вдруг?

Там получается что указатель на объект базового не всегда равен указателю на объект производного.

И что? static_cast умеет с этим справиться.

Соответственно помимо типа объекта вместо указателя на базовый класс необходимо хранить void*

не нужно.

seryoga ()
Ответ на: комментарий от seryoga

static_cast умеет с этим справиться

Вот дерьмо, действительно. Привык его для стандартных типов использовать и в своем варианте юзал reinterpret_cast, который ествественно приводил к моим проблемам.

По теме. Для решения Вашей задачи могу предложить пару методов.

1. Через виртуализацию

class Interface
{
    virtual bool IsDerived1() {return false;}
    virtual bool IsDerived2() {return false;}
};

class Derived1 : public Interface
{
    bool IsDerived1() override {return true;}
};

class Derived2 : public Interface
{
    bool IsDerived2() override {return true;}
};

2. Через перечислятор (но тут уже не интерфейс, а базовый класс)


enum class Type{isDerived1, isDerived2};

class Base
{
    Base(Type type) : m_type(type){}
    Type m_type;
};

class Derived1 : public Base
{
    Derived1() : Base(Type::isDerived1) {}
};


class Derived2 : public Base
{
    Derived2() : Base(Type::isDerived2) {}
};

Burns ()

кстати, в приведенном примере

 mumap.getinst<B>( ).somecall( ); 

почему нельзя сделать

 mumap.getinst<A>( ).somecall( ); 

ведь нужный somecall уже определен в виртуальной таблице, идущей от интерфейса A?

Burns ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.