Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Описание указателей?


Автор: BlHol 3.5.2006, 13:14
Добрый день!
Пытался задать этот вопрос в теме про указатели, но никто не отвечает, а нужно сильно срочно
Итак.
Маленький вопрос:

Такой код:
Код

TComponent *Obj = (TComponent *)Sender;



Первая часть (до "=") понятна:  указатель на объект класса.


А вот это как понимать?:
 
Код

(TComponent *)Sender;


Заранее благодарен.
С уважением.  
 

Автор: likehood 3.5.2006, 13:30
вообще-то, лучше так:
Код

TComponent *obj = dynamic_cast<TComponent*>(Sender);

то что справа от = это приведение указателя Sender к типу TComponent*. Это необходимо, поскольку Sender объявлен как TObject* Sender. Надо чтобы типы справа и слева от = совпадали, или неявно приводились один к другому. В данном случае неявное приведение невозможно, поэтому мы делаем его явно. Второй способ лучше, поскольку оператор dynamic_cast проверяет возможность приведения типа, а если оно невозможно, возвращает NULL. 

Автор: adonin 3.5.2006, 13:31
Это привидение типа. Я могу предположить (так как не вижу кода), что Sender - переменная типа void * 
Компилятор не позволит присвоить переменной с типом TComponent * значение переменной с типом void *. Хотя, и тот и тот тип  - это указатели, и занимают по 4 байта.
Чтобы сказать компилятору, что вы всё таки хотите выполнить такое присвоение, вы должны переопределить тип переменной Sender:
(Новый_тип)Переменная
В качестве нового типа вы указываете: Указатель на TComponent.  

Автор: Fazil6 3.5.2006, 13:31
Цитата

А вот это как понимать?:

это называется приведение типа, т.е. в данном выражении считать Sender указателем на TComponent 

Автор: adonin 3.5.2006, 13:31
Пока писал, ответили  smile  

Автор: Любитель 3.5.2006, 13:40
Судя по всему имеем:
1. TObject* sender (или какой там класс, суть в том, что TComponent - наследник TObject)
2. Хотим вызвать метод или обратиться к полю из TComponent (не TObject)
3. Знаем, что фактически sender указывает на экземпляр класс TComponent
Что делаем:
    (TComonent*) sneder - просто приводим к типу указателя на TComponent

ЗЫ Хотя лучше юзать reinterpret_cast 

Автор: Fazil6 3.5.2006, 13:50
Цитата

ЗЫ Хотя лучше юзать reinterpret_cast 

чем же лучше? dynamic_cast надо использовать 

Автор: cozzzy 3.5.2006, 18:37
Цитата(Любитель @  3.5.2006,  12:40 Найти цитируемый пост)
ЗЫ Хотя лучше юзать reinterpret_cast 

Не правда. 
Если каст делается в от родителя к наследнику. то юзается dynamic_cast

reinterpret_cast использовался бы, если sender - void* 

Автор: MAKCim 3.5.2006, 19:43
Цитата

Если каст делается в от родителя к наследнику. то юзается dynamic_cast

dynamic_cast используется при приведении указателя/ссылки 
на объект полиморфного базового класса к производному
Цитата

Компилятор не позволит присвоить переменной с типом TComponent * значение переменной с типом void *

если речь о C++  smile 
Цитата

reinterpret_cast использовался бы, если sender - void*  

зачем тогда reinterpret_cast? Лучше static_cast (если точно знаешь что void* Sender указывает на TComponent) 

Автор: cozzzy 3.5.2006, 20:56
Как раз для void* самое лучшее приведение - reinterpet_cast

Основное назначение static_cast - приведение простых типов вроде int->char, float->double 

Автор: LuckLess 4.5.2006, 15:47
Цитата(cozzzy @  3.5.2006,  20:56 Найти цитируемый пост)
Основное назначение static_cast - приведение простых типов вроде int->char, float->double  


ерунда.
static_cast единственно правильное решение для преобразования родитель - потомок , если уверен, что оно возможно.
dynamic_cast если не уверен. вообще dynamic_cast лучше не использовать.

вот попробуй примерчик.
Код

#include <iostream>

class A
   {
   int g[100];
   };
class B{};
class C:public A,public B{};


void main (void)
   {
   B* a = new C;
   std::cout << reinterpret_cast<C*>(a) << "\n"
            << static_cast<C*>(a);
   }

dynamic_cast тоже даст правельный результат, но зато убъет больше времени(значительно больше) + требует RTTI. 

Автор: LuckLess 4.5.2006, 16:13
вот примерчик на все преобразования, кому интересно.
Код

#include <iostream>

class B
   {
   int GG[100];
   public:
   virtual ~B(){};
   };

class C
   {
   public:
   virtual ~C(){};
   };

class A:public B,public C{};


void main (void)
   {
   C* c = new A;
   typedef A* pA;
   std::cout << reinterpret_cast<A*>(c) << "\n"
      << static_cast<A*>(c) << "\n"
      << dynamic_cast<A*>(c) << "\n"
      << (A*)c << "\n"
       << pA(c) << "\n";
   }

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

Автор: MAKCim 4.5.2006, 16:57
Цитата

dynamic_cast тоже даст правельный результат

в данном случае даже не скомпилируется   smile 
еще раз
Цитата

dynamic_cast используется при приведении указателя/ссылки 
на объект полиморфного базового класса к производному
 

Автор: LuckLess 4.5.2006, 17:03
Цитата(MAKCim @  4.5.2006,  16:57 Найти цитируемый пост)
в данном случае даже не скомпилируется  

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

Автор: MAKCim 4.5.2006, 19:24
Цитата

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

для каждого случая свой вариант преобразования
в случае неполиморфных классов (предок-потомок) - static_cast, в случае несвязанных никаким отношением классов - reinterpret_cast, в случае полиморфных - dynamic_cast
в твоем компилируемом варианте в общем случае безопасен только dynamic_cast
потому как в случае
Код

C* c=new C;
...
A* a=static_cast<A*>(c);

в a будет адрес предположительно (думает компилятор  smile ) объекта класса A, что не верно
dynamic_cast вернет 0 

Автор: LuckLess 4.5.2006, 19:40
Цитата(MAKCim @  4.5.2006,  19:24 Найти цитируемый пост)
в случае полиморфных - dynamic_cast

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

а static_cast работает одинаково как с полиморфнами типами, так и нет. 
хотя приведение предок - потомок в любом случае - ошибка стадии проектирования, но static_cast меньшая ошибка нежели dynamic , поскольку последний не просто гробит полиморфизм как понятие, но еще и тащит за собой тяжолую библиотеку + подторжаживает систему. 

Автор: MAKCim 4.5.2006, 21:08
Цитата

а static_cast работает одинаково как с полиморфнами типами, так и нет. 

см. мой предыдущий пост, не во всех случаях
Цитата

dynamic_cast убивает полиморфизм как понятие.

если неправильно применять, то любое средство языка гробит функциональность, для реализации которой оно вводилось
вообще dynamic_cast - полезная вещь, но, естественно все должно быть по делу   

Автор: LuckLess 4.5.2006, 21:30
пф. спорить чуствуеться бесполезно.

Цитата(MAKCim @  4.5.2006,  21:08 Найти цитируемый пост)
см. мой предыдущий пост, не во всех случаях

и что? что в том посте то? брр.
ясное дело что если робитель - не потомок, то статик каст наделает бед , также и реинтрепрет. не в этом дело совсем.
Это совершенно не означает что надо использовать динамик. если я точно знаю что родитель - на самом деле потомок - надо использовать статик и точка.


Цитата(MAKCim @  4.5.2006,  21:08 Найти цитируемый пост)
если неправильно применять, то любое средство языка гробит функциональность, для реализации которой оно вводилось
вообще dynamic_cast - полезная вещь, но, естественно все должно быть по делу    

Как динамик каст не применяй - он гробит ООП.
можно сказать что динамик каст в ООП - это goto в структурном программировании 

Автор: cozzzy 4.5.2006, 21:54
Цитата(LuckLess @  4.5.2006,  20:30 Найти цитируемый пост)
Как динамик каст не применяй - он гробит ООП.можно сказать что динамик каст в ООП - это goto в структурном программировании 


Цитата Bruce Eckel "Thinking in C++, vol.2":
Цитата

For most programs downcasting is unnecessary, and is actually discouraged, since everyday polymorphism solves most problems in object-oriented application programs. However, the ability to check a cast to a more derived type is important for utility programs such as debuggers, class browsers, and databases. C++ provides such a checked cast with the dynamic_cast operator


Добавлено @ 21:56 
И еще из MSDN:

Цитата

In general you use static_cast when you want to convert numeric data types such as enums to ints or ints to floats, and you are certain of the data types involved in the conversion. static_cast conversions are not as safe as dynamic_cast conversions, because static_cast does no run-time type check, while dynamic_cast does. A dynamic_cast to an ambiguous pointer will fail, while a static_cast returns as if nothing were wrong; this can be dangerous.
 

Автор: LuckLess 4.5.2006, 22:15
Цитата(cozzzy @  4.5.2006,  21:54 Найти цитируемый пост)
debuggers, class browsers, and databases

да яне спорю что иногда. оооочень редко динамик каст можно применить, но говорить в этом случая о полиморфизме нельзя!


Цитата(cozzzy @  4.5.2006,  21:54 Найти цитируемый пост)
static_cast returns as if nothing were wrong; this can be dangerous.

я и говорю, что статик надо использовать только кодга знаешь что родитель - потомок.  

Автор: MAKCim 4.5.2006, 22:35
Цитата

Это совершенно не означает что надо использовать динамик. если я точно знаю что родитель - на самом деле потомок - надо использовать статик и точка.

еще раз говорю, не всегда
Код

class A 
{
public:
    virtual ~A() {}
};

class B
{
public:
    virtual ~B() {}
};

class C {};

class D: public C, virtual public A, virtual public B
{
};

int main()
{
    A* a=new D;        // точно знаю, что родитель - потомок
    D* d=static_cast<D*>(a);      // не катит (в compile-time недостаточно информации)
    D* p=dynamic_cast<D*>(a);  // OK
    return 0;
} 

кстати, этот пример опрвергает Ваше утверждение
Цитата

а static_cast работает одинаково как с полиморфнами типами, так и нет. 

Цитата

Как динамик каст не применяй - он гробит ООП.
можно сказать что динамик каст в ООП - это goto в структурном программировании  

Вы не задавались вопросом, зачем он тогда вообще нужен?
и вообще
dynamic_cast - неотъемлимая часть RTTI, RTTI в общем случае нужен и оправдан т к (см. Дизайн и эволюция C++ ст. 321-322) => dynamic_cast как механизм RTTI оправдан и не надо его сравнивать с goto, который всегда можно заменить в коде и который делает этот код менее понятным
dynamic_cast нужен не только ради реализации подобного кода, который несомненно плох и применение в нем dynamic_cast неоправдано
Код

class A {...}; // полиморфный
class B: public A {...};
class C: public A {...};
...

void F(A* a)
{
    if (dynamic_cast<B*>(a)) {...}
   else if (dynamic_cast<C*>(a)) {...}
   else ...
}
 

ps. спор действительно бесполезный  

Автор: LuckLess 4.5.2006, 22:56
Цитата(MAKCim @  4.5.2006,  22:35 Найти цитируемый пост)
ps. спор действительно бесполезный  

:yes:
согласен с goto перебрал smile smile.
просто хочу сказать что надо стараться не использовать rtti и динамик каст если это возможно, а чаще всего это возможно.

 

Автор: cozzzy 4.5.2006, 23:26
Цитата(LuckLess @  4.5.2006,  21:56 Найти цитируемый пост)
просто хочу сказать что надо стараться не использовать rtti и динамик каст если это возможно, а чаще всего это возможно.

Возможно на счет использования dynamic_cast ты и прав, но чем тебе в целом RTTI не угодил? 

Автор: LuckLess 5.5.2006, 00:04
rtti в большинстве своем нарушает принципы ООпП.
да и медленный он..
 

Автор: Kostt 5.5.2006, 07:02
RTTI во многих случаях просто необходим. А самому его реализовывать - еще медленнее будет. Так что спор ни о чем. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)