К>... Подкиньте плиз линки, где хорошо написано про:
Три источника и три составные части: Мейерс, Саттер, Страуструп.
К>1. Все типы *_cast'ов, сравнение их между собой и с С-шным стилем, описаны различия.
Существует четыре точка 1 (по аналогии с DD 5.1) типа кастов — static_cast, dynamic_cast, const_cast и reinterpret_cast. .1 — это С-каст. Новые касты были введены вместо С-кастов в основном по двум причинам — для облегчения поиска преобразований в теле программы (для этого достаточно простого текстового поиска по "_cast") и уточнения намерений программиста. Кроме того, С-касты не в состоянии обеспечить функциональность dynamic_cast. Соответственно, они предлагают значительные преимущества по сравнению с традиционными С-кастами. К>2. Что конкретно происходит при вызове каждого из cast'ов, как обстоят дела, если например переопределён оператор приведения типа.
1. static_cast.
Используется для преобразований, основанных на статической проверке типов. Может применяться для преобразования перечислений в целые, целых во флоаты, казателя на базовый класс в указатель на производный класс. "Дешевый" оператор, не налагающий никаких накалдных расходов во время исполнения. Зачастую может вызываться неявно. Не способен выполнять "неродственные" преобразования, например из void* в int* или из А в несвязанный с ним родственными отношениями В, если не определены собственные операторы преобразования типов. В случае приведения указателя на базовый класс к указателю на потомка может оказаться небезопасным — гарантий того, указатель в момент выполнения будет указывать на экземпляр класса потомка, нет.
При необходимости статик-каст может вызывать пользовательские операторы преобразования типов.
2. dynamic_cast.
С-каст не способен реализовать его функциональность. Отличается от статик каста проверкой типов во время выполнения, следовательно, его использование сопряжено с накладными расходами и требует включения RTTI (Run-time type information), однако безопасно. Существует в двух формах — указательной и ссылочной. Пример:
class A {};
class B : public A {};
...
A a;
B b;
A* pa=&b;
A& ra=b;
B* pb=dynamic_cast<B*>(pa); //указательная форма
B& rb=dynamic_cast<B&>(ra); //ссылочная форма
Формы различаются поведением. в случае если во время выполнения программы проверка типов показала, что преобразование некорректно (например, указателя не указывает на объект запрашиваемого типа). Указательная форма возвращает нулевой указатель, а ссылочная генерирует исключени bad_cast.
3. const_cast.
Используется для снятия атрибутов const и volatile, что не способны сделать другие касты. Его нельзя использовать для преобразования типов по аналогии с предыдущими кастами. Применение этого оператора "успокаивает" компилятор на предмет изменения константного объекта, однако способно привести к неопределенному поведению, в случае, если память по данному адресу окажется непредназначенной для чтения на более низком уровне (например, заблокирована ОС). Может снять атрибут константности с this и вызывать неконстные методы внутри класса. Например:
struct A {
void f() {};
void cf() const;
};
void A::cf() {
f(); //compilation errorconst_cast<A*>(this)->f(); //ok, but probably unsafe
}
...
const A a;
a.cf();
4. reinterpret_cast.
Компилятор умывает руки. Используется для преобразований указателей на что угодно в указатели на что угодно другое. Единственное безопасное использование — преборазование туда и затем обратно. Все прочее — на совести программиста. Использование его в современной программе — повод всерьез задуматься о дизайне, современный С++ позволяет практически полностью от него отказаться. Однако, необходимо при использовании унаследованных библиотек.
struct A{
void f() {}
};
...
int i;
int *pi=&i;
A* pa=reintrepret_cast<A*>(pi);
pa->f(); //WHAT A MESS!! But compiles OK.
4.1 С-каст
Когда компилятор С++ видит С-каст, он по собственному разумению вызывает один из трех _кастов. Рекомендуется заменять на явное использование _каста для демонстрации намерений программиста.
К>3. Плюсы и минусы использования cast'ов.
Касты (особенно reinterpret) зачастую свидетельсвтуют о плохом дизайне программы. Их использование следует минимизировать, каждое появление в коде документировать, обосновывая их появление.
Да здравствует мыло душистое и веревка пушистая.
Re[4]: Разные способы приведения типов - где можно почитать?
Здравствуйте, Vamp, Вы писали:
B>>Если быть до конца точным, то: V>.... V>Какое это имеет отношение к кастам? Не говоря уже о том, что это не нужно в данном конкретном случае.
Это имеет самое непосредственное отношение к dynamic_cast. Понижающие преобразования возможны только для полиморфных типов, а для этого нужна хотя бы одна виртуальная функция.
Любите книгу — источник знаний (с) М.Горький
Re[2]: Разные способы приведения типов - где можно почитать?
V>2. dynamic_cast. V>С-каст не способен реализовать его функциональность. Отличается от статик каста проверкой типов во время выполнения, следовательно, его использование сопряжено с накладными расходами и требует включения RTTI (Run-time type information), однако безопасно. Существует в двух формах — указательной и ссылочной. Пример:
V>
V>class A {};
V>class B : public A {};
V>...
V>A a;
V>B b;
V>A* pa=&b;
V>A& ra=b;
V>B* pb=dynamic_cast<B*>(pa); //указательная форма
V>B& rb=dynamic_cast<B&>(ra); //ссылочная форма
V>
V>Формы различаются поведением. в случае если во время выполнения программы проверка типов показала, что преобразование некорректно (например, указателя не указывает на объект запрашиваемого типа). Указательная форма возвращает нулевой указатель, а ссылочная генерирует исключени bad_cast.
Если быть до конца точным, то:
class A
{
public:
virtual ~A(){}
};
class B : public A
{
public:
virtual ~B() {}
};
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re: Разные способы приведения типов - где можно почитать?
Здравствуйте, Vamp, Вы писали:
V>Проверка показала, что Комо отлично компилит и так:
V>struct B { };
V>struct D : private B { };
V>int main() {
V> D d;
V> B* bp = reinterpret_cast<B*>(&d);
V> B& br = reinterpret_cast<B&>(d);
V>}
V>Или я не так понял?
Не так. Cast notation в этом случае, в отличие от reinterpret_cast, гарантирует получение корректного указателя на подобъект базового класса. (Hint: множественное наследование)
Re[3]: Разные способы приведения типов - где можно почитать?
Здравствуйте, Vamp, Вы писали:
V> 4.1 С-каст V> Когда компилятор С++ видит С-каст, он по собственному разумению вызывает V> один из трех _кастов. Рекомендуется заменять на явное использование _каста V> для демонстрации намерений программиста.
C-style cast обладает некоторыми особенностями, отличающими его от любых
комбинаций static_cast, reinterpret_cast и const_cast: http://rsdn.ru/forum/?mid=523418
Здравствуйте, Vamp, Вы писали:
К>>3. Плюсы и минусы использования cast'ов. V>Касты (особенно reinterpret) зачастую свидетельсвтуют о плохом дизайне программы. Их использование следует минимизировать, каждое появление в коде документировать, обосновывая их появление.
Однако существует целый design pattern, целиком и полностью основанный на dynamic_cast’е — Acyclic Visitor.
Разные способы приведения типов - где можно почитать?
Уже несколько раз пытался разобраться со всеми этими *_cast'ами, но каждый раз запутывался, т.к. везде, где читал, это описано неупорядочено, сумбурно. Подкиньте плиз линки, где хорошо написано про:
1. Все типы *_cast'ов, сравнение их между собой и с С-шным стилем, описаны различия.
2. Что конкретно происходит при вызове каждого из cast'ов, как обстоят дела, если например переопределён оператор приведения типа.
3. Плюсы и минусы использования cast'ов.
Почему же, ё-моё, ты нигде не пишешь «ё»?
Re[3]: Разные способы приведения типов - где можно почитать?
Спасибо, Vamp. Основное теперь понял. Такие вопросы возникли:
V>1. static_cast. V>Не способен выполнять "неродственные" преобразования, например из void* в int* ...
А как тогда вообще преобразовать void* в int*?
V>При необходимости статик-каст может вызывать пользовательские операторы преобразования типов.
При какой необходимоси? Кто определяет, вызывать ли пользовательские операторы, или нет? И по какому критерию?
И ещё по стилю: есть же ситуации, когда без преобразования типов никак. Ну например, функция потока принимает параметр LPARAM. Как туда передать всё, что мне надо? Указатель. А как его передать совсем без использования операторов приведения типов? Как же тогда фраза о том, что современный С++ позволяет без них обходиться?
Почему же, ё-моё, ты нигде не пишешь «ё»?
Re[3]: Разные способы приведения типов - где можно почитать?
К>При какой необходимоси? Кто определяет, вызывать ли пользовательские операторы, или нет? И по какому критерию?
class A
{
public:
operator int()const;
};
class B
{
public:
B(int);
};
void g()
{
A a;
static_cast<int>(a);
static_cast<B>(10);
}
К>И ещё по стилю: есть же ситуации, когда без преобразования типов никак. Ну например, функция потока принимает параметр LPARAM. Как туда передать всё, что мне надо? Указатель. А как его передать совсем без использования операторов приведения типов? Как же тогда фраза о том, что современный С++ позволяет без них обходиться?
LPARAM — это не С++. Это скорее WinAPI'шный С
Of course, the code must be complete enough to compile and link.
Re[3]: Разные способы приведения типов - где можно почитать?
V>>1. static_cast. V>>Не способен выполнять "неродственные" преобразования, например из void* в int* ... К>А как тогда вообще преобразовать void* в int*?
Ну, я вообще-то ошибся. Такое преобразование статик каст способен выполнить. Нельзя преобразовать из int* в char*, например. Прошу прощения.
V>>При необходимости статик-каст может вызывать пользовательские операторы преобразования типов. К>При какой необходимоси? Кто определяет, вызывать ли пользовательские операторы, или нет? И по какому критерию?
Пользовательские операторы вызываются в случае, если они есть и такое преобразование без них не выполнить. В качестве таких операций могут выступать конструкторы.
К>И ещё по стилю: есть же ситуации, когда без преобразования типов никак. Ну например, функция потока принимает параметр LPARAM. Как туда передать всё, что мне надо? Указатель. А как его передать совсем без использования операторов приведения типов? Как же тогда фраза о том, что современный С++ позволяет без них обходиться?
А это не функция современного С++. Это как раз функция унаследованной библиотеки.
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Разные способы приведения типов - где можно почитать?
Здравствуйте, Lorenzo_LAMAS, Вы писали:
LL> Павел, при этом, как я понимаю, речь идет о static_cast аналогичном преобразовании сквозь закрытое наследование?
В формулировке сказано: "static_cast and reinterpret_cast operations", но, думаю,
в "нормальных" случаях все-таки подразумевается именно static_cast.
LL> На самом деле это на дыру похоже.
Учитывая, что для этого дела есть специальный пункт (5.4/7) — скорее, "фича"
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Разные способы приведения типов - где можно почитать?
ПК>C-style cast обладает некоторыми особенностями, отличающими его от любых ПК>комбинаций static_cast, reinterpret_cast и const_cast: ПК>http://rsdn.ru/forum/?mid=523418
Кроме того, в отличие от static_cast и reinterpret_cast, с помощью c-style cast можно приводить без соблюдения "прав доступа":
указатель/lvalue унаследованного класса — к указателю/ссылке базового класса:
struct B { };
struct D : private B { };
D d;
B* bp = (B*)&d;
B& br = (B&)d;
Проверка показала, что Комо отлично компилит и так:
struct B { };
struct D : private B { };
int main() {
D d;
B* bp = reinterpret_cast<B*>(&d);
B& br = reinterpret_cast<B&>(d);
}
Или я не так понял?
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Разные способы приведения типов - где можно почитать?
Здравствуйте, Batiskaf, Вы писали:
B>Если быть до конца точным, то:
... и оверхед уменьшить
B>
B>class A
B>{
B>public:
B>virtual ~A(){}
B>};
B>class B : public A
B>{
B>public:
B>/*virtual ~B() {}*/
B>};
B>
HgLab: Mercurial Server and Repository Management for Windows
Re: Разные способы приведения типов
От:
Аноним
Дата:
12.09.06 06:47
Оценка:
Здравствуйте, Vamp, Вы писали:
К>>3. Плюсы и минусы использования cast'ов. V>Касты (особенно reinterpret) зачастую свидетельсвтуют о плохом дизайне программы. Их использование следует минимизировать, каждое появление в коде документировать, обосновывая их появление.
А какая альтернатива их использованию?!
Например:
Class CViews{
...
CViews::CView
}
class B {
...
B::smth;
}
View = static_cast<CViews::CView *>(B.smth);
Re: Разные способы приведения типов - где можно почитать?
От:
Аноним
Дата:
12.09.06 06:49
Оценка:
Здравствуйте, Vamp, Вы писали:
К>>3. Плюсы и минусы использования cast'ов. V>Касты (особенно reinterpret) зачастую свидетельсвтуют о плохом дизайне программы. Их использование следует минимизировать, каждое появление в коде документировать, обосновывая их появление.
Здравствуйте, Vamp, Вы писали:
V>4. reinterpret_cast. V>Компилятор умывает руки. Используется для преобразований указателей на что угодно в указатели на что угодно другое.
Не всегда.
typedef void (*PF)();
void fun() {}
int main()
{
PF pf = &fun;
void* p = reinterpret_cast<void*>(pf);
}
"ComeauTest.c", line 7: error: invalid type conversion
void* p = reinterpret_cast<void*>(pf);
^
Хотя VC такое и без кастов проглатывает.
V>4.1 С-каст V>Когда компилятор С++ видит С-каст, он по собственному разумению вызывает один из трех _кастов.
Точнее сказать первый из списка
— a const_cast
— a static_cast
— a static_cast followed by a const_cast,
— a reinterpret_cast
— a reinterpret_cast followed by a const_cast
V>>4.1 С-каст V>>Когда компилятор С++ видит С-каст, он по собственному разумению вызывает один из трех _кастов. S>Точнее сказать первый допустимый из списка S>
S>— a const_cast
S>— a static_cast
S>— a static_cast followed by a const_cast,
S>— a reinterpret_cast
S>— a reinterpret_cast followed by a const_cast