К списку форумов К списку тем
Регистрация    Правила    Главная форума    Поиск   
Имя: Пароль:
Рекомендовать в новости

Помогите понять логику С++ кода

0 - 03.08.2012 - 22:57
Вот такой пример:

#include <iostream>
class Foo
**
public:
void foo()
**
std::cout << "hello world" << std::endl;
**
**;

int main()
**
Foo& foo = *(Foo*)NULL;
foo.foo();
**


Выводит на экран "Hello world", хотя по здравому смыслу, не должен.
Зачем компилятор позволяет вызывать метод несуществующего объекта?

Просьба ногами сильно не пинать, я старый паскалист и не понимаю высоких тонкостей C++.



1 - 03.08.2012 - 23:16
Вместо двойных звездочек у меня был символ открывающей фигурной скобки.
Гость
2 - 04.08.2012 - 01:02
imho
Вот я тоже смотрел на этот C++ и что то он мне не понравился. А так а почему бы ему не вызваться вот если бы в классе были данные и они бы использовались в конструкторе то да тогда были бы проблемы.
А код выглядит паршиво, кто же в ссылку сует Null ;) так же все их плюсы теряются.

Это что то типа классовых методов в delphi. Потом что из себя представляет указатель на метод класса в том же delphi это указатель на данные для конкретного экземпляра класса, а так же указатель на метод общий для всех экземпляров (ну это если упростить).

В данном случае экземпляр не создан т.е. для данных конкретного экземпляра класса foo память не выделялась, но сами то его методы есть. И поскольку в вызванном конструкторе нет обращения к данным экземпляра класса то все работает
Но все это мое Imho так C++ не использую, мне хватает простого C да и в прошивках для контроллеров там как то не до классов и прочих наворотов так как памяти обычно 1-4 КБ
Гость
3 - 04.08.2012 - 11:33
0-NTFS_ > ты старался сделать из молота дубину, тебе зачет, Санек. :)
Еще это бвает на стадии отладки, а что делать с вами? :)
4 - 04.08.2012 - 11:53
Это вообще не мой код :-) Я на С++ пишу только дипломы.
Просто возникла дискуссия с человеком, я считаю, что такой код работать не должен в силу здравого смысла.
Гость
5 - 04.08.2012 - 13:19
С чего вдруг оно не должно работать?
Как по Вашему, что означает сия запись "*(Foo*)NULL"?
6 - 04.08.2012 - 13:37
5-40KHYTbIU > Я не уверен, но, полагаю, что приведение указателя NULL к типу Foo. В привычных мне записях: TFoo(nil)
Гость
7 - 04.08.2012 - 13:38
4-NTFS_ > та я в курсе, что ты продажник :)
5-40KHYTbIU > Я ничо низнаю, но на Винде первые 64к как раз для этого и предназначены, типа чтобы нулл ловить.
8 - 04.08.2012 - 13:39
Суть противоречия:
Я утверждаю, что метод несозданного объекта не должен вызываться, если он не static (в терминах Паскаля - class function). Оппонент говорит, что может и должен, если не использует поля объекта.
Гость
9 - 04.08.2012 - 18:01
to8 Я соглашусь с вашим оппонентом, тем более это соответствует тому что я написал в посте 2.
То что это работает можете проверить запустив эклипс и создав тестовый проект с приведенным кодом. При дефолтных настройках проекта все собирается и запускается.
Гость
10 - 04.08.2012 - 18:23
более того возьмем Delphi и рассмотрим указатель на метод он описывается следующей структурой
TMethod = record
Code, Data: Pointer;
end;

Если описать класс и создать несколько его экземпляров, а затем для какого нибудь одного метода для всех экземпляров получить и проанализировать указатель на этот метод, то можно заметить, что Code будет указывать на одну и туже область памяти, а вот указатель Data будет уникален для каждого экземпляра.
Короче то куда указывает Code существует без создания экземпляра, при создании экземпляра лишь происходит выделение памяти для хранения данных экземпляра (ну это упрощенно).

И вот по этому если метод в классе не обращается к данным то его можно вызвать как классовый без создания экземпляра класса, кстати у классовых методов есть тоже ограничение - они тоже не должны обращаться к данным класса.

вот пример
пусть есть следующий класс
TTest=class(TObject)
public
procedure TestProc();
end;

procedure TTest.TestProc;
begin
ShowMessage('Test');
end;

так вот метод TestProc
может быть спокойно вызван как то вот так, но это все при условии что внутри TestProc нет обращения к данным класса
var
t:TTest;
begin
t:=nil;
t.TestProc;
end;
11 - 04.08.2012 - 21:23
Вы правы, этот код работает и для Delphi, и для FreePascal. Бред какой-то :-) ну какой смысл вызывать метод для несуществующего объекта? Метод - он ведь процедура объекта, а не просто процедура.
Ладно, спишу все на мою неграмотность и вернусь к своим проектам :-)
Спасибо всем, кто отозвался.
12 - 05.08.2012 - 17:26
>>Foo& foo = *(Foo*)NULL;
таким хитрым способом вы создаете ссылку на объект.

>>foo.foo();
здесь по ссылке на объект вызываете метод объекта.

Т.к. метод не пытается обратится к внутренним данным объекта(мемберам классам, полям)
поэтому ничего не падает.

Компилятор ничего не знает и не должен знать о том существует ли объект на самом деле или нет. Ведь ссылка могла быть получена из откуда угодна (из другой DLL например).

Требовать от С++ большего, это как требовать от оружия стрелять только в чужих и не стрелять в своих.

Такое оружие называется C#, Java и тд
Гость
13 - 06.08.2012 - 12:46
Тут просто песочница программистов, эдакий "С++ для начинающих". :)
NTFS_, ты же должен понимать, что метод с точки зрения физики - это та же самая функция, которой неявно передается указатель на начало участка памяти, где расположен объект, и больше никакого волшебства (у нас this, у вас Self). Не полезешь в "чужую" память - ничего тебе не будет. Все просто.
14 - 06.08.2012 - 12:54
13-And justice for all >
Хотелось бы, что при создании объекта устанавливался некий "флаг", говорящий методам: "Да, объект создан корректно и со мной можно работать без опасения получить Access Violation". А иначе может быть удивление, почему это половина методов работает, а половина - нет. Хотя дело в том, что просто забыли создать объект или неправильно передали ссылку.

Как я понимаю, C# и Java примерно так и делают. Фокус, описанный в 0, там не пройдет.
Гость
15 - 06.08.2012 - 13:20
14-NTFS_ > Про то, что С++ это ружжо, которым можно выстрелить себе в ногу, а можно убить и 2-х зайцев, уже не одно копье было сломано. Делайте выводы - С++ не для ссыкунов. :))))
Гость
16 - 06.08.2012 - 13:21
14-NTFS_ > Кстати, ты когда-нибудь сталкивался с тем, что тебе нужна копия объекта, а не ссылка на один и тот же в тех же C#, Java, VB? :)
17 - 06.08.2012 - 14:15
16-And justice for all > Я не работал профессионально в этих языках :-) Но копии объектов, конечно, регулярно нужны. На Delphi я тупо пишу метод CreateClone(). Вроде в некоторых языках это есть готовое, только компилятор не знает, что делать с вложенными объектами и начинаются падения. Короче, вручную лучше.
Гость
18 - 06.08.2012 - 14:19
to16 Кроме как в C++ я таких штук не видел, честно говоря так и не понял зачем оно вообще надо, точнее даже слабо представляю задачу в которой понадобился бы конструктор копий.
19 - 06.08.2012 - 14:50
18-TVV1 >
слабо представляю задачу в которой понадобился бы конструктор копий.
Мне это понадобилось, когда делал механизмы транзакций на стэке объектов. Нужно изменить объект - клонируем и работаем с ним, а остальные видят оригинальные объекты. Приходит коммит - удаляем все, кроме нужной копии.
Ну, еще для реализации паттерна "Команда" было очень удобно. Команды уже давно нет, а ее копия лежит в памяти, на случай отката.
Гость
20 - 06.08.2012 - 15:06
NTFS - "Хотелось бы, что при создании объекта устанавливался некий "флаг", говорящий методам: "Да, объект создан корректно и со мной можно работать без опасения получить Access Violation" - этот флаг - указатель this
void foo()
**
std::cout << (this? "hello world" : "oops!!!") << std::endl;
**
Гость
21 - 06.08.2012 - 18:29
17-NTFS_ > Компилятор как раз все знает. Он вызывает конструкторы копирования, которые либо реализованы программистом, либо компилятором (вы вольны решать), либо закрыты нафиг от шаловливых ручонок. По умолчанию производится побитовое копирование, а еще я люблю использовать STL. :)
ЗЫ: Это не означает, что я во всем согласен с товарищами стандартизаторами языка С++, ибо иногда все же кажется, что чуваки реально собрались побухать и поглумиться. :)
18-TVV1 > Правда что ли?? Офигеть, Вы в какой сфере применения ЯП работаете - где после нас хоть трава не расти? А про многопоточность когда-нибудь слышали? Как
там оперировать ссылками? Ждать, пока кто-то ее освободит?

20-vxg >Чисто теоретически, мы же как бы все знаем, что в релизной версии Access Violation может и не быть, если не нарушен был PAGE_GUARD.
Гость
22 - 07.08.2012 - 08:16
21 - просто указан способ для конкретного случая. в реальности такого никто никогда делать не будет.
OFF: про побухать и поглумиться несогласен, все предельно логично, где вы видели явный загон с их стороны?
Гость
23 - 07.08.2012 - 09:46
22-vxg > простейший пример - переприсваивание ссылки почему-то по их мнению можно и не ловить компилятором. Выглядит идиотски - код компилируется, но не работает. :)
Гость
24 - 07.08.2012 - 12:03
23 - что значит переприсваивание ссылки? ссылка инициализируется только при определении. после этого оператор "=" применяется к объекту на который смотрит ссылка. или я вас не так понял.
Гость
25 - 07.08.2012 - 15:50
24-vxg > Во-первых, можно на ты? Мы уже не раз тут копья ломали. :)
Во-вторых - да. Но это немного нелогично, на мой взгляд. При этом почему те же стандартизаторы когда-то решили, что компилятор ДОЛЖЕН как-то подсчитывать константную ссылку на временный объект, но при этом не должен считать неконстантную ссылку?
ЗЫ: Это еще о template разговор не зашел, там реально полет мысли. :) Ну и почему такую простую вещь, как свойства не приняли в новом стандарте.
Гость
26 - 07.08.2012 - 16:13
25 - что значит подсчитать? для удобства разработки придумали такое понятие как ссылка. ссылка инициализируется явно при определении или в полете если ссылка используется в качестве аргумента функции. ссылка не может быть константной или неконстантной - объект на который смотрит ссылка всегда один и изменить его нельзя. если нужно менять объект используют указатели. и это более чем логично. потому как ссылки задумывались как синонимы имен объектов. и если бы вы перенацеливали ссылку Ц с объекта А на объект Б человек был бы очень удивлен почему это переменная Ц так странно себя ведет - то одно с ней происходит до совершенно другое. с шаблонами тоже все более менее нормально. про свойства - да, неплохо было бы, а то без поддержки со стороны стандарта приходится либо делать как минимум один лишний доступ к компоненту объекта на котором можно что то забыть либо использовать зависимые от среды придумки вроде __property что не хочется делать исходя из переносимости. но видимо слишком много людей по разному представляющих себе это)
Гость
27 - 07.08.2012 - 17:42
26-vxg > Да нинадаминялечить. Ты отлично понял, о чем я говорил, упоминая константную ссылку - ясен пень, что объект, на который она ссылается. Дай мне еще ссылку на стандарт, ога, как это любят на рсдн.
Но ты так и не ответил - что мешало(мешает) сделать ссылку на неконстантный объект?
Гость
28 - 08.08.2012 - 00:49
Цитата:
Сообщение от And justice for all Посмотреть сообщение
Правда что ли?? Офигеть, Вы в какой сфере применения ЯП работаете - где после нас хоть трава не расти? А про многопоточность когда-нибудь слышали? Как там оперировать ссылками? Ждать, пока кто-то ее освободит?
То с чем работаю C, CoDeSys ST - это для контроллеров - тут вроде как без потоков обходится, но вместо них есть прерывания, они по сути создают те же проблемы что и потоки. Для доступа к разделяемых данным обычно использую аналог критической секции или запрет прерываний. Внутри критической секции обычно просто делаю копирование нужных данных в локальный буфер, а уже потом их спокойно обрабатываю ну это что бы не затягивать обработку прерываний долгой блокировкой критической секции.
Верхний уровень пишется на Delphi (TurboExplorer), тут я стараюсь с потоками не злоупотреблять без крайней необходимости. Но все же когда возникает такая необходимость, то тут обычно я использую два варианта, либо сам класс пишется с учетом что к нему будут обращаться из разных потоков, т.е. в нем будет реализована необходимая синхронизация доступа, либо пишется класс который будет обеспечивать синхронизацию доступа нескольких потоков к разделяемым ресурсам. Причем в первом варианте я обычно не заморачиваюсь тем для чего поток захватывает ресурс, только прочитать или еще и модифицировать, а вот во втором случае с отдельным классом для синхронизации обычно учитывается то для чего поток захватывает ресурс и там несколько читающих потоков могут иметь одновременный доступ к ресурсу, естественно что модификация ресурсов выполняется только при монопольном доступе.

И при всем этом для работы с потоками мне ни разу не понадобился аналог конструктора копий реализованного в C++.
Гость
29 - 08.08.2012 - 00:58
Да еще добавлю, что в контроллерах обычно мало ресурсов 1-16Кб flash, 1-2Кб SRAM, 512 байт EEPROM, ну это те что программирую на C, так что там не до классов и прочего. А вот те что на CoDeSys там ресурсов обычно дофига, но с CoDeSys ST (это некая помесь паскаля, бейсика и С) не разгонишься, да и архитектура там закрытая.
Гость
30 - 08.08.2012 - 08:36
27 - ??? нифига я не понял.
int x = 1; //вот объект, в нем храниться "1"
int &x_ref = x; //вот ссылка нацеленная на объект "x"
x_ref = 2; //помещаем внутрь объекта "x" на который нацелена ссылка "x_ref" значене "2"
const int &x_ref2 = x; //вот ссылка нацеленная на объект "x" который рассматривается как константный
//x_ref2 = 3; //...поэтому так мы сделать не можем
Гость
31 - 09.08.2012 - 14:06
28-TVV1 > "И при всем этом для работы с потоками мне ни разу не понадобился аналог конструктора копий реализованного в C++." - это прямо повезло.

30-vxg > Черт, я имел в виду неконстантную ссылку на временный объект.

string f()
** return string("Foo string"); **

...

const string &constRefStr = f(); // Так нормально.
string &refStr = f(); // Это не по стандарту C++2003.

Почему, вот вопрос. Один из множества вопросов и пожеланий, точнее. :)
Гость
32 - 09.08.2012 - 15:24
31 - эта ссылка называется ссылкой на константу. не знаю почему вы думаете, что стандарт 2003 не допускает создание ссылок не на константы. может какая-то нестандартная реализация? смотрю документ ANSI ISO IEC 14882 2003 стр. 150 и вижу в примере конструкции вида
int i;
int &r = i;
Гость
33 - 09.08.2012 - 15:25
на документе надпись second edition 2003-10-15. может у тебя другой?
Гость
34 - 09.08.2012 - 15:26
...а, понял о чем речь... думаю)
Гость
35 - 09.08.2012 - 15:42
хм. все равно в том документе который у меня есть нет явных запретов на подобные вещи. в старом стандарте компилится спокойно. где надыбать компилер с 2003 что бы проверить и будет ли поведение этого продукта соответствующим стандарту - на знаю
Гость
36 - 09.08.2012 - 15:55
а по поводу бессмысленности объекта по адресу NULL есть такая новость. при реализации средствами стандартного C++ такого понятия как свойства нужно каким-то образом получать доступ к this. что бы не передавать this явно в конструктор свойства один человек придумал вычислять его при помощи вычитания из адреса свойства смещения начала блока свойств которое может быть получено из объекта с начальным адресом NULL. http://www.codenet.ru/progr/cpp/cpp-...ties.php?rss=1
Гость
37 - 09.08.2012 - 19:27
14 если программа написана на C# такое будет не допустимо ((MyClass)null).MyMethod(), однако, в IL допустим этот случай для вызовов не виртуальных методов.

Но есть еще в c# такая весчь как extension method, и там такое допустимо ((MyClass)null).MyMethod(). по понятным причинам.
Гость
38 - 09.08.2012 - 19:40
16 "... Кстати, ты когда-нибудь
сталкивался с тем, что тебе нужна
копия объекта, а не ссылка на один
и тот же в тех же C#... "

В c# есть valued типы и reference типы. Есть также интерфейс IClonable.
Гость
39 - 10.08.2012 - 12:27
35-vxg > так далеко я не зашел, чтобы прочитать весь стандарт на английском. :)
Компилятор MSVS 2008 выдает предупреждение (кажется, на warning level 4), иногда RSDN мониторю..

38-simoncat > я в курсе. Кстати, с какой версии ввели valued-типы для не-POD типов (назовем их в терминах С++ User-defined, сложными, короче)?


К списку вопросов
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск




Copyright ©, Все права защищены