Пару логических задач для новичков)
| |
vasua99 | Дата: Воскресенье, 22 Апреля 2012, 21:47 | Сообщение # 1 |
GNU follower
Сейчас нет на сайте
| Code #include <cstdio> class A { public: virtual void p(int n = 0) { printf("%d",n); } };
class B : public A { public: virtual void p(int n = 2) { printf("%d",n); } };
int main() { A* my = new B(); my->p(); // it out "0" delete my; return 0; } Почему так?
Жизнь игра, и мы в ней пешки... А я кушаю пельмешки)
|
|
| |
TimKruz | Дата: Воскресенье, 22 Апреля 2012, 22:02 | Сообщение # 2 |
старожил
Сейчас нет на сайте
| Quote (vasua99) Пару логических задач для новичков) Я думал, что тут выложены именно задачи... Quote (vasua99) Почему так? Что - "так"? Почему «//it out "0"» («это выведет "0"») или что? Ты конкретней пиши, что ли...
|
|
| |
vasua99 | Дата: Воскресенье, 22 Апреля 2012, 22:06 | Сообщение # 3 |
GNU follower
Сейчас нет на сайте
| прочитай интерфейсы классов А и В,а теперь вопрос,почему выводится 0,а не 2
Жизнь игра, и мы в ней пешки... А я кушаю пельмешки)
|
|
| |
Нохчи | Дата: Воскресенье, 22 Апреля 2012, 22:13 | Сообщение # 4 |
заслуженный участник
Сейчас нет на сайте
| Компилятор до момента выполнения не знает, что A *my на самом деле указатель на класс B, поэтому пихает 0 в качестве аргумента.
Многие вопросы по Windows отпадут, если посмотреть тут
|
|
| |
Matou | Дата: Воскресенье, 22 Апреля 2012, 23:13 | Сообщение # 5 |
Исходный коТ
Сейчас нет на сайте
| Люблю этот язык.
|
|
| |
Йакуд | Дата: Понедельник, 23 Апреля 2012, 01:28 | Сообщение # 6 |
участник
Сейчас нет на сайте
| vasua99, дело в том, что четко указан тип объекта класса А. Т.к. метод является виртуальным, то реализация того или много виртуального метода будет определятся во время исполнения программы. Т.к. класс B наследуется от класса A, то мы имеем возможность создавать объекты с типом родителя, но не наоборот! Так вот, во время выполнения, программа видит, что используется объект класса A, следовательно вызывает его виртуальный метод. Вот как-то так =)
"Хороший художник – копирует, гениальный – ворует!" — Pablo Picasso .blanco 2.0
Сообщение отредактировал Йакуд - Понедельник, 23 Апреля 2012, 01:29 |
|
| |
Matou | Дата: Понедельник, 23 Апреля 2012, 02:25 | Сообщение # 7 |
Исходный коТ
Сейчас нет на сайте
| Quote (Йакуд) Т.к. класс B наследуется от класса A, то мы имеем возможность создавать объекты с типом родителя, но не наоборот! Так вот, во время выполнения, программа видит, что используется объект класса A, следовательно вызывает его виртуальный метод.
|
|
| |
Нохчи | Дата: Понедельник, 23 Апреля 2012, 04:50 | Сообщение # 8 |
заслуженный участник
Сейчас нет на сайте
| Йакуд, вызывается как раз метод класса В.
Многие вопросы по Windows отпадут, если посмотреть тут
|
|
| |
Archido | Дата: Понедельник, 23 Апреля 2012, 05:57 | Сообщение # 9 |
Сэнсэй
Сейчас нет на сайте
| Quote (Йакуд) дело в том, что четко указан тип объекта класса А. Т.к. метод является виртуальным, то реализация того или много виртуального метода будет определятся во время исполнения программы. Т.к. класс B наследуется от класса A, то мы имеем возможность создавать объекты с типом родителя, но не наоборот! Так вот, во время выполнения, программа видит, что используется объект класса A, следовательно вызывает его виртуальный метод. Вот как-то так =) Не так, выше уже написали об этом.
Дефолтные значения параметров функций компилятор ставит на основе простого анализа кода: нашел вызов функции определенного класса (в данном случае A->p(); ) и воткнул туда "0", неявно превратив код из "my->p();" в "my->p(0);".
А вызываться всегда будет функция класса B, т.к. при конструировании объекта данного класса используется именно таблица виртуальных функций класса B (здравствуй кэп) и потому, что функция "p()" переопределена в этом классе (B) - она и будет вызвана.
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
Сообщение отредактировал Archido - Понедельник, 23 Апреля 2012, 05:59 |
|
| |
Тритон | Дата: Понедельник, 23 Апреля 2012, 10:26 | Сообщение # 10 |
постоянный участник
Сейчас нет на сайте
| Quote (Йакуд) vasua99, дело в том, что четко указан тип объекта класса А. Т.к. метод является виртуальным, то реализация того или много виртуального метода будет определятся во время исполнения программы. Т.к. класс B наследуется от класса A, то мы имеем возможность создавать объекты с типом родителя, но не наоборот! Так вот, во время выполнения, программа видит, что используется объект класса A, следовательно вызывает его виртуальный метод. Вот как-то так =) Бред. При номинальном типе B нельзя создать объект с фактическим типом родителя, а как раз наоборот. И так как метод виртуальный, то будет вызван метод, соответствующий фактическому типу, то есть B::p();. Но полиморфизм распространяется только на поведение, не затрагивая значения параметров по умолчанию, а номинальный тип A. Таким образом, вызывается версия метода из класса B, но со значением параметра по умолчанию, определённом в классе A.
Не всё так плохо, как оно есть на самом деле.
|
|
| |
vasua99 | Дата: Понедельник, 23 Апреля 2012, 15:25 | Сообщение # 11 |
GNU follower
Сейчас нет на сайте
| Ответ:потому что сигнатура смотрится по базовому классу,когда вызывается виртуальный метод,а значит и подставляется 0,а не 2.
Новая задача(профи не пишите!Охото услышать новичков,т.к такой вопрос могут иногда на собеседовании задать)): как не использую третью переменную,обменять значения двух переменных(я знаю только два варианта,может кто еще знает))
Жизнь игра, и мы в ней пешки... А я кушаю пельмешки)
|
|
| |
Matou | Дата: Понедельник, 23 Апреля 2012, 15:44 | Сообщение # 12 |
Исходный коТ
Сейчас нет на сайте
| Quote (vasua99) я знаю только два варианта,может кто еще знает Знаю я кое-кого кто знает.
|
|
| |
Archido | Дата: Понедельник, 23 Апреля 2012, 15:51 | Сообщение # 13 |
Сэнсэй
Сейчас нет на сайте
| Quote (vasua99) потому что сигнатура смотрится по базовому классу,когда вызывается виртуальный метод,а значит и подставляется 0,а не 2. Не по базовому, а по тому, который указан в качества типа переменной и у которой впоследствии дергаем функцию.
Поэтому писать параметры по умолчанию у виртуальных функций плохой тон (даже смысла это не имеет), а если не знаешь об этой "особенности" можно убить много часов на попытку найти в чем же все таки дело Ну, в немалых проектах конечно. По хорошему компиляторы должны выдавать хотя бы warning в таких делах, но увы
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
Сообщение отредактировал Archido - Понедельник, 23 Апреля 2012, 16:08 |
|
| |
Snuux | Дата: Вторник, 24 Апреля 2012, 13:10 | Сообщение # 14 |
постоянный участник
Сейчас нет на сайте
| Quote (vasua99) Новая задача(профи не пишите!Охото услышать новичков,т.к такой вопрос могут иногда на собеседовании задать)): как не использую третью переменную,обменять значения двух переменных(я знаю только два варианта,может кто еще знает)) Так, я как раз новичек, так что мб скорее всего неправильно, но по идее, недавно читал, что это можно сделать с помощью ссылки.
P.S. Добавляй ещё задачки)
|
|
| |
Тритон | Дата: Вторник, 24 Апреля 2012, 13:17 | Сообщение # 15 |
постоянный участник
Сейчас нет на сайте
|
Добавлено (24.04.2012, 13:15) --------------------------------------------- Quote (Snuux) что это можно сделать с помощью ссылки. Ссылка - это только синоним некой переменной.
Добавлено (24.04.2012, 13:16) --------------------------------------------- Quote (vasua99) :потому что сигнатура смотрится по базовому классу,когда вызывается виртуальный метод,а значит и подставляется 0,а не 2. Такой бред и мне не снести. Сигнатура смотрится по номинальному классу.
Добавлено (24.04.2012, 13:17) --------------------------------------------- Quote (vasua99) я знаю только два варианта,может кто еще знает Интересно, какой же второй.
Не всё так плохо, как оно есть на самом деле.
Сообщение отредактировал Тритон - Вторник, 24 Апреля 2012, 13:24 |
|
| |
Apati | Дата: Вторник, 24 Апреля 2012, 13:21 | Сообщение # 16 |
заслуженный участник
Сейчас нет на сайте
| Quote (Тритон) a&=b; b&=a; a&=b; Сам-то тестировал)? Code #include <iostream> int main() { unsigned char a=5,b=6; a&=b; b&=a; a&=b; std::cout<<(int)a<<" "<<(int)b<<std::endl; return 0; } выводит: 4 4
UPD: так уже верно Второй способ: a+=b; b=a-b; a=a-b; правда он плохой, т.к. если а и б в сумме превышают максимально допустимое значение для типа, то будет ошибка
Сообщение отредактировал Apati - Вторник, 24 Апреля 2012, 13:27 |
|
| |
Тритон | Дата: Вторник, 24 Апреля 2012, 13:25 | Сообщение # 17 |
постоянный участник
Сейчас нет на сайте
| Quote (Apati) Сам-то тестировал)? Подзабыл соответствия значков логическим операторам. Исправил.
Не всё так плохо, как оно есть на самом деле.
Сообщение отредактировал Тритон - Вторник, 24 Апреля 2012, 13:25 |
|
| |
vasua99 | Дата: Вторник, 24 Апреля 2012, 14:00 | Сообщение # 18 |
GNU follower
Сейчас нет на сайте
| Ответ(ы): Code void swap1(int&a, int&b) { a -= (b = (a += b) - b); }
void swap2(int& a, int& b) { a ^= (b ^= (a ^= b)); }
3.Напишите функцию,меняюшую рандомно местами все символы.подсказка: может использовать предыдущую функцию обмена значениями например так: Code void swap(char& arg1,char& arg2); char str[] = "Hello"; swap(str[0],str[4]); printf("%s",str); // выведет oellH Добавлено (24.04.2012, 13:54) --------------------------------------------- П.с все символы в строке) Добавлено (24.04.2012, 14:00) --------------------------------------------- И вот еще потруднее задачка среднячкам(которую я сам не решил) Code void swap(int& a,int& b); char str[] = "Hello"; swap(str[0],str[4]); // str - oellH Каким образом происходит преобразование символов при вызове функции обмена значениями,и(мне это интереснее всего) как строка не портится при этом(у мея есть предположение что при неявном преобразовани при вызове функции происходит дополнение до 4х байт(т.е 3 байта,т.к символ занимает 1 байт)из памяти в другом месте)
Жизнь игра, и мы в ней пешки... А я кушаю пельмешки)
|
|
| |
Matou | Дата: Вторник, 24 Апреля 2012, 14:12 | Сообщение # 19 |
Исходный коТ
Сейчас нет на сайте
| Quote (vasua99) Каким образом происходит преобразование символов при вызове функции обмена значениями,и(мне это интереснее всего) как строка не портится при этом(у мея есть предположение что при неявном преобразовани при вызове функции происходит дополнение до 4х байт(т.е 3 байта,т.к символ занимает 1 байт)из памяти в другом месте) Я несколько раз прочитал и вообще ничего не понял.
|
|
| |
vasua99 | Дата: Вторник, 24 Апреля 2012, 14:29 | Сообщение # 20 |
GNU follower
Сейчас нет на сайте
| короче смотри целый тип занимает 4 байта,а символ 1 байт, у нас есть строка (любая к примеру) тобишь массив символов.так вот при вызове функции обмена значениями (см выше) происходит неявное преобразование из ссылки на символ (который находится в массиве) в ссылку на целое.Но каким образом оно происходит?
Жизнь игра, и мы в ней пешки... А я кушаю пельмешки)
|
|
| |
|