E>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого. E>По идее можно проверить vptr, но к нему кроскомпиляторно не подберешься, да и всякие случаи вроде множественного наследования...
Абстрактный виртуальный kind_of в базовом классе.
Типа:
enum ST {
eS2, eS3
};
struct S {
virtual ST kind_of() const = 0;
};
struct S2 : S {
virtual ST kind_of() const { return eS2; }
};
struct S3 : S {
virtual ST kind_of() const { return eS3; }
};
int main(int argc, char* argv[])
{
S2 s;
S3 s2;
void *p = &s;
void *p2 = &s2;
ST a = ((S*)p)->kind_of();
ST b = ((S*)p2)->kind_of();
return 0;
}
Но ИМХО стремно это как то, если потерять контроль над кодом.
Здравствуйте, nen777w, Вы писали:
N>Абстрактный виртуальный kind_of в базовом классе.
Это все конечно здорово, вот только не всегда работает
ST kindOf(void* p) { return ((S*)p)->kind_of(); }
int i;
kindOf(&i); // упсstruct One { int t; };
struct Two : One, S2 {};
Two t;
kindOf(&t); // если Two хранится в памяти как (One, S2) - будут грабли
Здравствуйте, TarasB, Вы писали:
TB>Здравствуйте, enji, Вы писали:
E>>Хочется узнать, указывает ли void* на конкретный тип TB>Крестопроблемы отсутствия общего предка в иерархии, да?
конечно если у тебя бесконечная память, ты можешь позволить себе пихать указатель на vptr+RTTI в каждый объект
только как производительностью запахнет — так сразу С да С++
Здравствуйте, Abyx, Вы писали:
A>конечно если у тебя бесконечная память, ты можешь позволить себе пихать указатель на vptr+RTTI в каждый объект A>только как производительностью запахнет — так сразу С да С++
Здравствуйте, TarasB, Вы писали:
A>>конечно если у тебя бесконечная память, ты можешь позволить себе пихать указатель на vptr+RTTI в каждый объект A>>только как производительностью запахнет — так сразу С да С++
TB>Ок, а почему нельзя вызвать typeid?
typeid вернет "void*" потому что оно не знает где брать RTTI для объекта.
Здравствуйте, enji, Вы писали:
E>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого.
Где и почему происходит переход к void*? Возможно этот переход можно заменить на что-то типа boost::any?
E>По идее можно проверить vptr, но к нему кроскомпиляторно не подберешься, да и всякие случаи вроде множественного наследования...
Да и не поможет он в общем случае. void* может указывать на double, который случайно может выглядеть как правильный vptr.
Здравствуйте, Abyx, Вы писали: A>typeid вернет "void*" потому что оно не знает где брать RTTI для объекта.
Почему нельзя все объекты, для которых ты хочешь знать тип, унаследовать от MyBaseRootObject, и вместо void* брать MyBaseRootObject*?
И typeid надо брать не от указателя, а от того, что по нему.
Здравствуйте, TarasB, Вы писали:
TB>Здравствуйте, Abyx, Вы писали: A>>typeid вернет "void*" потому что оно не знает где брать RTTI для объекта.
TB>Почему нельзя все объекты, для которых ты хочешь знать тип, унаследовать от MyBaseRootObject, и вместо void* брать MyBaseRootObject*? TB>И typeid надо брать не от указателя, а от того, что по нему.
Здравствуйте, Abyx, Вы писали:
TB>>Почему нельзя все объекты, для которых ты хочешь знать тип, унаследовать от MyBaseRootObject, и вместо void* брать MyBaseRootObject*? TB>>И typeid надо брать не от указателя, а от того, что по нему.
A>ты вообще знаешь как работает RTTI?
яркое доказательство того, кому на самом деле не нравится С++ =)
зы
TarasB — один из самых ярых ненавистников С++ на говноког.ру
(сужу не только по нику)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, enji, Вы писали:
E>>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого.
EP>Где и почему происходит переход к void*? Возможно этот переход можно заменить на что-то типа boost::any?
boost::any не умеет доставать указатели по иерархии, только в точности то, что туда положили. Есть попытка dynamic_any (гугл в помощь), но там какие-то принципиальные сложности были, ЕМНИП, я помню было обсуждение в буст-листе, по наводке alnsn
Еще можно boost::variant, если известен набор возможных базовых классов.
Но если этот void* — это просто замыкание в стиле Си (коллбэк + контекст) или какой-нть GetWindowLong (если я правильно помню заклинание), то, имхо, ничего тут проверять не надо, достаточно просто в документации написать, что по этому указателю обязан быть наследник Base.
Либо действительно завести реестр, но компилировать его, естественно, только в отладочной версии.
Здравствуйте, jazzer, Вы писали:
E>>>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого. EP>>Где и почему происходит переход к void*? Возможно этот переход можно заменить на что-то типа boost::any? J>boost::any не умеет доставать указатели по иерархии, только в точности то, что туда положили. Есть попытка dynamic_any (гугл в помощь), но там какие-то принципиальные сложности были, ЕМНИП, я помню было обсуждение в буст-листе, по наводке alnsn
Да, any_cast требует точного типа. Я имел ввиду своё type-erasure (возможно на Boost.TypeErasure), которое даст возможность неинтрузивно сделать все необходимые проверки, выполнить все операции, но:
J>Еще можно boost::variant, если известен набор возможных базовых классов.
этот вариант лучше/проще.
Кстати, наткнулся на вот это обсуждение (ты про него говорил? там и alnsn отметился).
Там is_derived проверка делается через abuse исключений.
J>Но если этот void* — это просто замыкание в стиле Си (коллбэк + контекст) или какой-нть GetWindowLong (если я правильно помню заклинание), то, имхо, ничего тут проверять не надо, достаточно просто в документации написать, что по этому указателю обязан быть наследник Base.
Никогда не делал проверки в подобных местах — не было таких требований надёжности.
Здравствуйте, TarasB, Вы писали:
TB>Здравствуйте, enji, Вы писали:
E>>Хочется узнать, указывает ли void* на конкретный тип TB>Крестопроблемы отсутствия общего предка в иерархии, да?
да как скзать. С одной стороны — да, с другой — тут погоня за миниоптимизациями, которые в "некрестах" просто невозможны Можно было сделать это все в плюсовом стиле на boost::signals2 к примеру, таких проблем бы не возникло
Здравствуйте, jazzer, Вы писали:
J>Почему у тебя void*, а не Base*, для начала?
Есть собственный мини-фреймворк для сигналов-слотов, с разными плюшками, вроде предобработки сигнала, фильтрации и т.д. Пока сделал его так, что наследование от Base (да и к тому ж виртуального Base) не требуется ни для источника, ни для получателей. И по пути boost::function (с наворачиванием шаблонного наследника интерфейса) идти пока не охота — обошелся просто указателями на объект и на статическую функцию.
Дальше в рамках решения прикладной задачи захотелось написать универсальный фильтр, которому как раз хорошо бы понять тип получателя. Пока обошелся просто внешним реестром. Но задумался, нельзя ли понять тип динамически, исследую структуру объекта, на который указывает void*
J>Но если этот void* — это просто замыкание в стиле Си (коллбэк + контекст) или какой-нть GetWindowLong (если я правильно помню заклинание), то, имхо, ничего тут проверять не надо, достаточно просто в документации написать, что по этому указателю обязан быть наследник Base.
Вот кстати тож интересный вопрос
struct Base {
virtual ~Base();
virtual int f();
};
struct Some { int a; };
struct S1 : Some, Base {} s1;
struct S2 : Base {} s2;
struct S3 : Base, Some {} s3;
int func(void *o) {
return static_cast<Base*>(o)->f();
}
func(&s1); // упс
func(&s2); // ок
func(&s3); // скорее всего ок
Как я понимаю, на msvc и gcc надо потребовать, чтобы Base был "первым" наследником
Здравствуйте, enji, Вы писали:
E>Здравствуйте, jazzer, Вы писали:
J>>Почему у тебя void*, а не Base*, для начала?
E>Есть собственный мини-фреймворк для сигналов-слотов, с разными плюшками, вроде предобработки сигнала, фильтрации и т.д. Пока сделал его так, что наследование от Base (да и к тому ж виртуального Base) не требуется ни для источника, ни для получателей. И по пути boost::function (с наворачиванием шаблонного наследника интерфейса) идти пока не охота — обошелся просто указателями на объект и на статическую функцию.
А почему бы в таком случае не использовать boost::function напрямую (или вообще boost::signal)? Он шаблонов не требует, у него тип нормальный, а в замыкание при конструировании что угодно можно засунуть, не нужно никаких дополнительных void*-параметров.
E>Дальше в рамках решения прикладной задачи захотелось написать универсальный фильтр, которому как раз хорошо бы понять тип получателя. Пока обошелся просто внешним реестром. Но задумался, нельзя ли понять тип динамически, исследую структуру объекта, на который указывает void*
Нет, нельзя. dynamic_cast мог бы, но он не работает с void*, ему нужен указатель на объект реального класса.