Сообщений 59 Оценка 306 [+2/-10] Оценить |
Список литературы |
Мальвина дала Буратино 3 яблока, потом забрала назад одно. Вопрос: Сколько яблок осталось у Буратино? Ответ: Да кто его знает. Неизвестно, сколько яблок у него было до этого!
Может ли C++ быть веселым? Давайте проверим! :) Я знаю несколько примеров, которые радуют программистский взгляд. И предлагаю взглянуть!
Разомнемся на кошках. Представьте, что вы видите следующий код:
int i = 5; int j = i++ + ++i; |
Чему будет равно j? Вы хорошо подумали? Дело в том, что правильный ответ – где-то от 10 до 14! Мой любимый GCC выдает 12, но это еще не предел. Стандарт C++ не обязывает, чтобы результат оператора ++ был вычислен до операции присвоения, поэтому ответ может меняться от компилятора к компилятору, и даже зависеть от ключей оптимизации. Ведь результат операции i = i++, и тот не определен! Желающие могут погуглить "C++ Sequence point", а мы пойдем дальше. :)
Как вы думаете, возможен ли такой код:
int x[x]; int y = y; j j; int i::i = j.j; |
Как ни странно, вполне возможен, если сделать так:
const int x = 1; constint y = 2; struct j { int j; }; namespace i { int x[x]; int y = y; j j; int i::i = j.j; }; |
Перекрытие видимостей делает свое черное дело! :) Впрочем, MS Visual C++ такой код не берет: объявление “int j” он считает объявлением конструктора, а тот, как известно, не может возвращать значение. А вложенная переменная “y”, несмотря на «инициализацию», будет иметь произвольное значение (если окажется автоматической). И это хороший признак того, что с подобными «приемами» баловаться не стоит!
Возьмем еще один интересный синтаксический пример. С этого примера началась моя коллекция приколов, и его я люблю больше всего. Ведь он, помимо всего прочего, содержит еще и психологический трюк. Смотрите сами:
T t1; T t2(t1); T t3 = t1; T t4(); |
Какой конструктор вызовется в каждом из четырех случаев? Если вы решили, что это:
то вы ошиблись... дважды! Первым, конечно, идет конструктор по умолчанию, а вторым – конструктор копирования, что очевидно следует из синтаксиса. Но в третьем случае, несмотря на знак "=", у нас все равно срабатывает старый добрый конструктор копирования: ведь мы создаемновый объект, а не инициализируем существующий! В последнем же случае это вообще не создание объекта, а... объявление функции, которая не принимает параметров и возвращает тип T, сравните:
int foo(); |
Если вы ни разу не ошиблись – я вас поздравляю. Если все-таки разок да ошиблись и теперь жаждете реванша – то вот вам еще одна возможность! Пускай у вас есть такой класс:
class A { public: A() { printf("default\n"); } A(long) { printf("long\n"); } explicit A(int) { printf("int\n"); } A(const A&) { printf("copy\n"); } A &operator=(const A&) { printf("op=\n"); } }; |
Есть и использующий его код:
void prn(int n) { cout << n << ": "; } int main() { constint i = 0; prn(1); A a1(); prn(2); A a2 = i; prn(3); A a3(i); prn(4); A a4 = A(i); prn(5); A a5 = (A) i; prn(6); A a6 = static_cast<A>(i); return 0; } |
Что в данном случае выведется на экран? Скажу честно, я сам здесь ошибся, причем жестоко и не один раз. Поэтому думайте внимательнее. Прикинули? Правильный ответ таков:
1: 2: long 3: int 4: int 5: int 6: int |
Единица, понятное дело, пуста – как вы помните, это объявление функции. Двойка не смогла построить класс из int’а – он ведь explicit, но компилятор услужливо конвертнул int в long – а там, гляди – конструктор уже имеется. Остальные варианты – это вариации на тему A(i), просто по-разному оформленные. Можно только заценить грамотность транслятора, который ни разу не использовал лишние конструктор копирования или оператор присваивания, и даже конструктор по умолчанию. На то он и С++! :)
И последний пример, может быть, самый «практичный» из приведенных. Пускай вам надо сделать цикл, в котором значение переменной стремится к нулю. Конечно, можно воспользоваться оператором for. Но ведь можно сделать и так:
int i = 10; while (i --> 0) { cout << i << endl; } |
А называется эта конструкция – оператор "стрелка". :)
Вот такие штуки возможны в нашем родном :) языке. А там, глядишь, подоспеет C++0x (скорей бы уж!), где, я думаю, нас ожидает еще немало подобных приколов. А пока давайте помнить, что этот код все-таки шутка, а не руководство к действию! :) (от редакции – когда будете вставлять смайлики в код, не забудьте предварять их знаками комментария!) :)
Сообщений 59 Оценка 306 [+2/-10] Оценить |