Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
Господа, будьте снисходительны, не бросайтесь сразу штрафовать за, как вам кажется, глупые вопросы - beginners на то и beginners.
| |
по поводу исключений - вычитано в msdn`е, да и нулевой указатель он не возвращает (хотя, судя по тому же msdn`у - должен) 09.12.04 16:43 Число просмотров: 2468
Автор: zelych Статус: Member
|
|
<beginners>
|
заморочка с dynamic_cast 09.12.04 15:11
Автор: zelych Статус: Member
|
решил тут, как-то попользовать dynamic_cast (не слишком я люблю rtti, но тут вот приспичило)..
как написано в msdn`е, если dynamic_cast не может преобразовать указатель к нужному типу генерируется исключение bad_cast, а если объект по указателю вообще не содержит rtti информации, то генерируется исключение __non_rtti_object..
ну а мне как-раз этого-то и надо.. хотел отделять мусорные указатели от настоящих..
не получилось..
вот небольшой исходничек:
#include <stdio.h>
class A {
int x;
public:
A(){ x = 0; }
int fun() { return x; }
};
class B : public A {
public:
B() { y = 1; }
int y;
};
void* get_ptr() { return */(void-1 /*/ new B/**/; }
void main()
{
A *x, *y = (A*) get_ptr();
try {
x = dynamic_cast<A*>( y );
} catch(...){
x = 0;
}
if( x ) printf( "%i", x->fun() );
}
вроде правильно, и rtti в свойствах проекта включил, только вот компилятор почему-то генерирует такой вот код (в release конфигурации):
void main()
{
A *x, *y = (A*) get_ptr();
try {
x = dynamic_cast<A*>( y );
00401000 or eax,0FFFFFFFFh
} catch(...){ x = 0; }
if( x ) printf( "%i", x->fun() );
00401003 mov eax,dword ptr [eax]
00401005 push eax
00401006 push offset string "%i" (4060FCh)
0040100B call printf (401016h)
получается, что на весь RUN-TIME в rtti ему пофигу..
просвятите, пожалуйста, откуда трабл такой..
|
|
Вообще-то dynamic_cast от указателя возвращает нулевой указатель, а не швыряет исключение. 09.12.04 16:34
Автор: Ktirf <Æ Rusakov> Статус: Elderman
|
|
| |
по поводу исключений - вычитано в msdn`е, да и нулевой указатель он не возвращает (хотя, судя по тому же msdn`у - должен) 09.12.04 16:43
Автор: zelych Статус: Member
|
|
| | |
Ну что сказать - безобразие, что не возвращает... 10.12.04 14:04
Автор: Ktirf <Æ Rusakov> Статус: Elderman
|
В целом по использованию приведений типа см. цитату amirul'а из Страуструпа. А надежного способа определения мусорных указателей в C++, увы, нет и не предвидится.
|
| | | |
Универсального способа определения мусорного указателя вообще не существует, имхо (update) 10.12.04 15:24
Автор: amirul <Serge> Статус: The Elderman Отредактировано 10.12.04 15:34 Количество правок: 3
|
> В целом по использованию приведений типа см. цитату > amirul'а из Страуструпа. А надежного способа определения > мусорных указателей в C++, увы, нет и не предвидится. Вернее можно внедрить в язык то, что можно сделать средствами C++ уже сейчас. Речь о том, чтобы сделать ВСЕ классы своей иерархии наследниками одного базового, например CObject
Ну и после этого делать что то типа:
class CObject {
private:
static const unsigned long ExpectedSignature = 0x12345678; // Какое нить достаточно случайное число
unsigned long Signature;
public:
CObject(): Signature(ExpectedSignature) {}
virtual ~CObject() = 0;
bool IsObject() {
__try {
return (Signature == ExpectedSignature);
} __except (EXCEPTION_EXECUTE_HANDLER) {
return false;
}
}
};
---
ну и использовать как нибудь так:
void
f(void *ptr) {
CObject *object = reinterpret_cast<CObject *>(ptr);
if (object->IsObject()) {
deriv = dynamic_cast<CMyDerivedClass *>(object);
} else {
throw bad_cast();
}
}
---
Вероятность того, что под этим указателем будет память и при этом будет содержать нужную сигнатуру будет меньше, чем 2^(-32)
Хотя эта самая сигнатура является ничем иным как полем типа, которое в C++ не рекомендуется. Опять таки повторюсь, что не знаю ни одной ситуации, которая бы привела к ПОЛНОЙ потере информации о типе в C++. Скорее всего дизайн проекта сделан не совсем верно. Если скажут, какую задачу нужно решить с помощью динамического кастования, то возможно мы найдем другой способ
-----------------
В вышеприведенном коде вместо микрософтовского SEH вполне можно использовать стандартные try/catch блоки
|
|
Для использования RTTI класс должен быть абстрактным 09.12.04 15:42
Автор: amirul <Serge> Статус: The Elderman
|
> class A { > int x; > public: > A(){ x = 0; } > int fun() { return x; } > }; > > class B : public A { > public: > B() { y = 1; } > int y; > }; То бишь иметь виртуальные функции.
> просвятите, пожалуйста, откуда трабл такой.. А вообще использование RTTI чаще всего говорит о плохой архитектуре проекта. Лучше пересмотри, мож чего можно сделать с помощью обычных виртуальных функций и статической типизации
|
| |
Неправда твоя. 09.12.04 16:29
Автор: Ktirf <Æ Rusakov> Статус: Elderman
|
Для использования RTTI необходимо и достаточно включить флажок у компилятора.
|
| | |
Ладно, мож это устаревшая информация 09.12.04 16:37
Автор: amirul <Serge> Статус: The Elderman
|
> Для использования RTTI необходимо и достаточно включить > флажок у компилятора. Как доберусь до страуструпа - скажу точнее. Но я точно помню, что он писал про то, что инфа для RTTI хранится в vtbl-е, а vtbl создается если есть виртуальные функции. Мож это расширение от микрософта, а мож я чего-й-то гоню. Надо проверить
|
| | | |
Добрался до страуструпа 10.12.04 12:50
Автор: amirul <Serge> Статус: The Elderman
|
Итак
1. Для кастинга, который можно сделать обычным static_cast-ом (от дочернего класса к базовому) поведение dynamic_cast-а совпадает со статическим.
2. Для downcasting-а (вниз по иерархии, то бишь от базового к наследнику) необходимо чтобы кастуемая переменная (а не тип в который она кастуется) имела полиморфный (перед этим я ошибочно назвал его абстрактным) тип. То бишь иметь виртуальные функции.
То есть, если хочется сделать
dynamic_cast<T *>(ptr);
То ptr - ОБЯЗАТЕЛЬНО должен иметь полиморфный тип, а T - может быть любым (в том числе и конкретным классом)
3. dynamic_cast к указателю в случае ошибки всегда возвращает NULL. Исключения бросает кастинг к ссылке:
dynamic_cast<T &>(var);
в случае когда такое приведение невозможно (во всех случаях когда вернулся бы указатель NULL)
Теперь замечания. Я не могу придумать ни одного случая, когда в C++ полностью теряется информация о типе (то бишь об указателе известно только то, что он void *). Вообще в C++ не так уж часто применяется (void *)
|
| | | | |
спасибо, теперь вроде ясно.. 10.12.04 18:02
Автор: zelych Статус: Member
|
> 1. Для кастинга, который можно сделать обычным > static_cast-ом (от дочернего класса к базовому) поведение > dynamic_cast-а совпадает со статическим.
похоже, именно это и происходит..
> Теперь замечания. Я не могу придумать ни одного случая, > когда в C++ полностью теряется информация о типе (то бишь > об указателе известно только то, что он void *). Вообще в > C++ не так уж часто применяется (void *)
а я, вот, придумал..
трабл такой получается при объединении моих объектов с WinAPI..
|
| | | | | |
И где именно ты теряешь тип? 10.12.04 18:57
Автор: amirul <Serge> Статус: The Elderman
|
> а я, вот, придумал.. > трабл такой получается при объединении моих объектов с > WinAPI.. Не верю :-)
Сам неоднократно швырял указатели в WinAPI. Но при этом точно знал, что как минимум на какой-то базовый объект данный указатель указывает. Уточни задачу - мож чего и придумаем
|
| | | | | | |
CreateWindow -> CBT Hook 14.12.04 16:54
Автор: zelych Статус: Member
|
> Сам неоднократно швырял указатели в WinAPI. Но при этом > точно знал, что как минимум на какой-то базовый объект > данный указатель указывает. Уточни задачу - мож чего и > придумаем
В CreateWindow последним аргументом кладу указатель на некоторый объект, который будет ассоциироваться с окном..
При этом, хуком отлавливаю все создания окон и заношу в списочек hwnd окна и через CBT_CREATEWND вытаскиваю lpParam - последний аргумент CreateWindow..
Естественно, пару лишних движений мышкой - и винда насоздаёт кучу окошек, у которых lpParam указыавет на какую-то хрень..
вот их-то и надо отсеять..
такие дела..
и ещё до кучи.. что бы немного отвлечься..
В msdn`е написано:
"Bitmaps as Brushes
A number of functions use the brush currently selected into a device context to perform bitmap operations. For example, the PatBlt function replicates the brush in a rectangular region within a window, and the FloodFill function replicates the brush inside an area in a window bounded by the specified color (unlike PatBlt, FloodFill does fill nonrectangular shapes). "
получается что можно использовать картинку в качестве кисточки, хотело поробовать, но не получилось.. никак не ругается, но вместо картинок просто белым цветом закрашивает..
|
| | | | | | | |
Ну тогда наверное сигнатурку надо, как выше показано 14.12.04 17:58
Автор: amirul <Serge> Статус: The Elderman
|
> получается что можно использовать картинку в качестве > кисточки, хотело поробовать, но не получилось.. никак не > ругается, но вместо картинок просто белым цветом > закрашивает.. Я с GDI не слишком, но сделал ли ты SelectObject перед рисованием.
|
| | | | | | | | |
С этим делом разобрался.. 15.12.04 12:16
Автор: zelych Статус: Member
|
причём совершенно мистическим способом:
сегодня утром решил ещё раз посмотреть хелп.. вместо раздела Bitmaps открываю Brushes->Brush Functions и обнаруживаю там CreatePatternBrush..
|
| |
не катит [upd] 09.12.04 16:03
Автор: zelych Статус: Member Отредактировано 09.12.04 16:10 Количество правок: 1
|
> То бишь иметь виртуальные функции.
class A {
int x;
public:
A(){ x = 0; }
virtual int fun() { return x; }
};
class B : public A {
public:
B() { y = 1; }
int y;
virtual int fun() { return y; }
};
вроде как, теперь есть..
компилятор генерирует точно такой же код (один в один)..
похоже, что компилятор считает себя очень умным, и решил run-time не использовать..
> А вообще использование RTTI чаще всего говорит о плохой > архитектуре проекта. Лучше пересмотри, мож чего можно > сделать с помощью обычных виртуальных функций и статической > типизации
ну, наверное, не зря он есть..
а если без него, то как?? всё что приходит мне в голову, можно рассматривать как собственную реализацию rtti.. иначе придумать не умею..
[upd] PS имхо, абстрактные - классы у которых не все функции реализованы.. и в с++ их делать нельзя..
|
|
|