Оценка 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 (скорей бы уж!), где, я думаю, нас ожидает еще немало подобных приколов. А пока давайте помнить, что этот код все-таки шутка, а не руководство к действию! :) (от редакции – когда будете вставлять смайлики в код, не забудьте предварять их знаками комментария!) :)
Оценка 306
[+2/-10]
Оценить ![]() ![]() ![]() ![]() ![]() ![]()
|