| 
 
 
 
 Легенда:
  новое сообщение 
  закрытая нитка 
  новое сообщение 
  в закрытой нитке 
  старое сообщение   | 
Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
Новичкам также крайне полезно ознакомиться с данным документом.
Господа, будьте снисходительны, не бросайтесь сразу штрафовать за, как вам кажется, глупые вопросы - beginners на то и beginners. 
|  |  |  |  | Добрался до страуструпа  10.12.04 12:50  Число просмотров: 2580 Автор: 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 *)
 |  | <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 имхо,  абстрактные - классы у которых не все функции реализованы.. и в с++ их делать нельзя..
 |  
 
 
 |  |