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


Автор: novice2011 16.2.2012, 09:00
Код

#include<iostream>
using namespace std;

class Low
{
private:
     int hold;
public:
    Low(const int h = 0) : hold(h) {}
    virtual void show() const {cout << "hold " << hold << endl;}    
};

class High : public Low
{
private:
    double boom;
public:
    explicit High(double db = 0, int h = 0) : boom(db), Low(h) {}
    virtual void show() const { Low::show(); cout << "boom " << boom << endl; }    
};

int main()
{    
    const int b = 2;
    const int & x = b;
    int c = const_cast<int &>(x);
    c = 3;
    cout << c << ' ' << x << ' ' << b << endl; // с = 3; x и b = 2;    
    const High bar(77.7, 7);
    bar.show();    
    High *dar;
    dar = const_cast<High*>(&bar);
    *dar = High(999.9, 222);        
    dar->show();    
    bar.show();    
    return 0;
}
     

Переменная b объявлена с идентификатором const, поэтому операция  const_cast не может изменить ее значение. Объект bar так же объявлен с идентификатором const, однако операция  const_cast меняет его значение. Вопрос, почему? По идее, не должна.

Автор: boostcoder 16.2.2012, 09:17
Цитата(novice2011 @  16.2.2012,  09:00 Найти цитируемый пост)
поэтому операция  const_cast не может изменить ее значение. 

не по этому. у тебя ошибка в коде.

найди десять отличий ;) : http://liveworkspace.org/code/2a4c89cc868dec36c04b0059b7543f6e

Добавлено через 1 минуту и 20 секунд
Цитата(novice2011 @  16.2.2012,  09:00 Найти цитируемый пост)
поэтому операция  const_cast не может изменить ее значение

и если бы он не мог - ты бы получил ошибку компиляции.

Добавлено через 1 минуту и 46 секунд
с ссылками все по взрослому smile 

Автор: novice2011 16.2.2012, 10:59
Цитата(boostcoder @ 16.2.2012,  09:17)
у тебя ошибка в коде.



Уважаемый, boostcoder, ввиду своей неопытности я не понял, а где именно ошибка в коде? Не смогли бы вы пояснить?

Автор: mes 16.2.2012, 11:08
Цитата(novice2011 @  16.2.2012,  09:59 Найти цитируемый пост)
 а где именно ошибка в коде? Н

одна тут :
Цитата(novice2011 @  16.2.2012,  08:00 Найти цитируемый пост)
 int c = const_cast<int &>(x);

int& c =...

Автор: novice2011 16.2.2012, 11:18
Цитата(mes @ 16.2.2012,  11:08)
int& c =...

Да, вы правы, но после исправления этой ошибки все остается по-прежнему.

Автор: mes 16.2.2012, 11:45
Цитата(novice2011 @  16.2.2012,  10:18 Найти цитируемый пост)
 но после исправления этой ошибки все остается по-прежнему. 

все ли ?  с этой ошибкой не происходило изменения значения, а сейчас происходит, даже если вывод этого не показывает  smile
вообщем если у вас выводится старое значение, то  это не чудеса  smile, а проделки компилятора  smile
вот это поможет поправить вывод :
Код

    volatile const int b = 2;
    volatile const int & x = b;
    int& c = const_cast<int &>(x);

Автор: novice2011 16.2.2012, 12:12
Да, но в этом коде дело даже не в переменной с.  Просматривая литературу, я прочитал: "Операция const_cast не во всем хороша. Она может изменить указатель на величину, но эффект от изменения значения, заданного как const, не определен". В этом же коде объект bar объявляется как const, но тем не менее, с помощью операции const_cast его можно изменить, что противоречит выше приведенной цитате из книги Стивена Прата. Вот этого я и не пойму.

Автор: xvr 16.2.2012, 12:24
Цитата(novice2011 @  16.2.2012,  12:12 Найти цитируемый пост)
что противоречит выше приведенной цитате

Не противоречит. 'не определен' это не значит 'не меняется', это значит 'может быть что угодно', т.е. может и поменяться, а может и нет

Автор: mes 16.2.2012, 12:25
Цитата(novice2011 @  16.2.2012,  11:12 Найти цитируемый пост)
его можно изменить, что противоречит 

 а чем противоречит ?! 

Автор: novice2011 16.2.2012, 12:27
Понял, всем большое спасибо!

Автор: mes 16.2.2012, 12:40
novice2011,  для полноты понимания, нужно учитывать что бывает три вида констант:
1. реальныя константа рантайма, находящаяся  в read-only памяти - менять такую  никогда нельзя 
например char *str = "hello";  из за совместимости можно присвоить реальный константный объект неконстантной переменной, но изменение ее чревато исключением.. 

2. логическая константа - обычная переменная помеченная квалификатором const - такие менять с помощью const_cast относительно  безопасно, за исключением проявления шуток оптимизатора, как у вас в примере..

3. константное выражение - это константа времени компиляции и не неаходится в памяти.. 
так например выражение  
 const int size = 4; 
создает одну константную переменную,которую можно изменить и ассоциированное с ним константное выражение, которое можно применять например при создании массивов
 int arr[size];
при этом размер массива будет равен первоначальному значению, даже если вы до этого изменили size через конст_каст.. 

smile

Автор: novice2011 16.2.2012, 12:45
Да, поясню, что вопросы у меня возникли после этого примера:


Код

#include <iostream>
using std::cout;
using std::endl;

void change(const int * pt, int n);

int main()
{
    int pop1 = 38383;
    const int pop2 = 2000;
    
    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
    change(&pop1, -1);
    change(&pop2, -1);
    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;

    return 0;
}

void change(const int * pt, int n)
{
    int * pc;
    if (n < 0)
    {
        pc = const_cast<int *>(pt);
        *pc = 100;
    }
}


Вывод программы: pop1, pop2: 38383, 2000
pop1, pop2: 100, 2000
Т.е здесь pop2 не изменяется, поэтому я и попробовал применить const к объекту класса. Но объект класса в результате поменял свое значение, в отличие от pop2 в этом примере.

Автор: mes 16.2.2012, 13:24
Цитата(novice2011 @  16.2.2012,  11:45 Найти цитируемый пост)
Т.е здесь pop2 не изменяется

опять та же ошибка в понимании..  "не изменяется" и "выводится старое значение" это разное поведение smile

можно вот так заставить компилятор выводить актуальное значение константы :
Код

    cout << "pop1, pop2: " << pop1 << ", " <<  const_cast<int&>(pop2) << endl;


Автор: novice2011 16.2.2012, 15:01
Спасибо, mes.

Автор: boostcoder 17.2.2012, 04:09
Цитата(novice2011 @  16.2.2012,  11:18 Найти цитируемый пост)
после исправления этой ошибки все остается по-прежнему. 

Цитата(mes @  16.2.2012,  11:45 Найти цитируемый пост)
с этой ошибкой не происходило изменения значения, а сейчас происходит, даже если вывод этого не показывает

зачем вы гадаете? http://liveworkspace.org/code/2a4c89cc868dec36c04b0059b7543f6e-то я на что дал?

Автор: LeonidPr 17.2.2012, 09:33
Цитата(mes @ 16.2.2012,  11:45)
Цитата(novice2011 @  16.2.2012,  10:18 Найти цитируемый пост)
 но после исправления этой ошибки все остается по-прежнему. 

все ли ?  с этой ошибкой не происходило изменения значения, а сейчас происходит, даже если вывод этого не показывает  smile
вообщем если у вас выводится старое значение, то  это не чудеса  smile, а проделки компилятора  smile
вот это поможет поправить вывод :
Код

    volatile const int b = 2;
    volatile const int & x = b;
    int& c = const_cast<int &>(x);

Заинтересовала эта тема (особенно в плане проделок компилятора), решил попробовать запустить этот пример с вашими исправлениями. И столкнулся с интересной особенностью компиляторов. После сборки и запуска примера в C++ Builder 5 получил вывод в консоли: 3 3 2 (т.е. в качестве значения b выводится то, что ей присвоили). Компиляция этого примера компилером gcc дала результат: 3 3 3. Возможно необходимо ковырять настройки Builder-а, но оптимизацию я полностью отключил.
Решил посмотреть, что-же генерит Builder. Скормил exe-шник ida и получил следующее (комментарии мои):
Код

.text:00401150 ; int __cdecl main(int argc,const char **argv,const char *envp)
.text:00401150 _main           proc near              
.text:00401150 
.text:00401150 var_c           = dword ptr -0Ch
.text:00401150 var_x           = dword ptr -8
.text:00401150 var_b           = dword ptr -4
.text:00401150 argc            = dword ptr  8
.text:00401150 argv            = dword ptr  0Ch
.text:00401150 envp            = dword ptr  10h
.text:00401150 
.text:00401150                 push    ebp
.text:00401151                 mov     ebp, esp
.text:00401153                 add     esp, 0FFFFFFCCh

;volatile const int b = 2
.text:00401156                 mov     [ebp+var_b], 2

;volatile const int  &x = b
.text:0040115D                 lea     eax, [ebp+var_b]
.text:00401160                 mov     [ebp+var_x], eax

;int &c = const_cast<int &>(x)
.text:00401163                 mov     edx, [ebp+var_x]
.text:00401166                 mov     [ebp+var_c], edx

;c = 3
.text:00401169                 mov     ecx, [ebp+var_c]     ;в ecx загружаем адрес b
.text:0040116C                 mov     dword ptr [ecx], 3   ;меняем значение b

;cout << c
.text:00401172                 mov     eax, [ebp+var_c]
.text:00401175                 push    dword ptr [eax]
.text:00401177                 push    ds:@std@cout    ; std::cout
.text:0040117D                 call    @std@_basic_ostream$c19std@_char_traits$c__@$blsh$qi ; std::basic_ostream<char,std::char_traits<char>>::operator<<(int)
.text:00401182                 add     esp, 8
;cout << x
.text:00401185                 mov     edx, [ebp+var_x]
.text:00401188                 push    dword ptr [edx]
.text:0040118A                 push    ds:@std@cout    ; std::cout
.text:00401190                 call    @std@_basic_ostream$c19std@_char_traits$c__@$blsh$qi ; std::basic_ostream<char,std::char_traits<char>>::operator<<(int)
.text:00401195                 add     esp, 8
;cout << b (собственно то, что искали)
.text:00401198                 push    2
.text:0040119A                 push    ds:@std@cout    ; std::cout
.text:004011A0                 call    @std@_basic_ostream$c19std@_char_traits$c__@$blsh$qi ; std::basic_ostream<char,std::char_traits<char>>::operator<<(int)

Получается, как было уже сказано mes, "не изменяется" и "выводится старое значение" это разное поведение.
Компилятор при выводе константы запихнул в стек не то значение, которое расположено в памяти, выделенной для этой константы, а то значение, которым её инициализировали при объявлении.

Автор: mes 17.2.2012, 09:37
Цитата(boostcoder @  17.2.2012,  03:09 Найти цитируемый пост)
зачем вы гадаете? 

гадание это ко мне относится ? ну так я не знаю  же результатов именно тс, даже если по ссылке показывает эту ошибку  smile 

Автор: boostcoder 17.2.2012, 14:08
Цитата(mes @  17.2.2012,  09:37 Найти цитируемый пост)
даже если по ссылке показывает эту ошибку

не понял..
т.е. http://liveworkspace.org/code/2a4c89cc868dec36c04b0059b7543f6e результат не верный?

Добавлено через 57 секунд
ааа, точно smile 
странно...

Автор: boostcoder 17.2.2012, 14:54
newbee бдит!

Автор: novice2011 18.2.2012, 13:31
Да, уж, теперь я точно понял, что совершенно ничего не понял.

Автор: bsa 18.2.2012, 14:19
novice2011, а что тут понимать? Язык С++ очень мощный. На нем можно и легкое быстрое приложение состряпать для встраиваемого девайса, а можно и распределенную систему промышленного уровня написать за вменяемые сроки. Но за все надо платить: язык содержит в себе ряд спорных особенностей (иногда даже ошибок проектирования самого языка), которые при неправильном использовании могут сильно усложнить жизнь. Поэтому, чтобы все эти особенности освоить, нужно огромное время изучения и практики.
Если ты чувствуешь в себе силы всю жизнь учиться, а так же желание писать программы, то добро пожаловать к нам - С/С++ программистам. Если же тебе хочется только попробовать, то можешь начать с что-нибудь попроще.

Автор: novice2011 18.2.2012, 19:56
Спасибо, bsa. Хочется стать таким же грамотным, как ребята, которые помогли мне уяснить некоторые моменты, поэтому остается только утроить свои усилия по изучению языка.

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