Только что с собеседования.
И попался такой вопрос (см ниже):
#include"iostream"class A { public: virtual void f() =0; };
class B { public: virtual void f() { std::cout<< "My string"<<std::endl; } };
void main()
{
// обращаю внимание, что троиточия между кодом нет, весь код "как есть".
A *a = 0; // здесь именно нули
B *b = 0; // здесь именно нули
//a->f();
b->f();
}
Если я не ошибаюсь, то была именно такая запись. Был вопрос, как поведёт себя программа. Правильный ответ был озвучен так: если снять комментарий с "a->f();", то программа ругнется Unhandle (так и было мною сказано), а вот b->f(); должен выдать строку "My string"
И сослались на устройство виртуальной таблицы и стандарт (после поста сразу лезу в стандарт, что бы узнать).
Попробовал на MSVC 2008, b->f() также выдало Unhadled.
Это был гон, или ошибка компилятора Действительно ли это так?
p.s. Если тут окажется человек с которым я сегодня беседовал прошу подключиться к топику.
это действительно так. никакого "My string" там конечно же не вывелось бы.
надо где-то иметь ссылку на ТВФ, поэтому валидный указатель на объект крайне желателен.
но конкретный компилятор, с конкретными опциями (макс оптимизация, например) может выполнить вторую строчку.
Но это ничего не значит.
---
С уважением,
Сергей Мухин
Re[2]: после Собеседования... остались вопросы
От:
Аноним
Дата:
18.08.09 12:21
Оценка:
Здравствуйте, Ovl, Вы писали:
Ovl>это действительно так. никакого "My string" там конечно же не вывелось бы. Ovl>надо где-то иметь ссылку на ТВФ, поэтому валидный указатель на объект крайне желателен.
T_T>Попробовал на MSVC 2008, b->f() также выдало Unhadled. T_T>Это был гон, или ошибка компилятора Действительно ли это так?
T_T>p.s. Если тут окажется человек с которым я сегодня беседовал прошу подключиться к топику.
Будет работать без virtual
class A {public: void f() { std::cout << "hello world!" << std::endl;};
void main(void)
{
A* a = 0;
a->f();
}
в таком случае должно выдаться hello world потому что нет никаких таблиц виртуальных функций. а сама функция f() имеет фиксированный адрес в памяти.
Вообще для компилятора не виртуальная функция это просто функция, которой неявно передается this. функция примерно равна
Здравствуйте, catBasilio, Вы писали:
B>Здравствуйте, The_Thing, Вы писали:
T_T>>Попробовал на MSVC 2008, b->f() также выдало Unhadled. T_T>>Это был гон, или ошибка компилятора Действительно ли это так?
T_T>>p.s. Если тут окажется человек с которым я сегодня беседовал прошу подключиться к топику.
B>Будет работать без virtual
B>
B> class A {public: void f() { std::cout << "hello world!" << std::endl;};
B> void main(void)
B> {
B> A* a = 0;
a->>f();
B> }
B>
B>в таком случае должно выдаться hello world потому что нет никаких таблиц виртуальных функций. а сама функция f() имеет фиксированный адрес в памяти.
B>Вообще для компилятора не виртуальная функция это просто функция, которой неявно передается this. функция примерно равна
B>
Здравствуйте, The_Thing, Вы писали:
T_T>Если я не ошибаюсь, то была именно такая запись. Был вопрос, как поведёт себя программа. Правильный ответ был озвучен так: если снять комментарий с "a->f();", то программа ругнется Unhandle (так и было мною сказано), а вот b->f(); должен выдать строку "My string" T_T>И сослались на устройство виртуальной таблицы и стандарт (после поста сразу лезу в стандарт, что бы узнать).
дурной вопрос. можно разве что какой-либо ход мысли учитывать как правильный/неправильный, но не такой ответ.
Здравствуйте, Alexander G, Вы писали:
T_T>>Если я не ошибаюсь, то была именно такая запись. Был вопрос, как поведёт себя программа. Правильный ответ был озвучен так: если снять комментарий с "a->f();", то программа ругнется Unhandle (так и было мною сказано), а вот b->f(); должен выдать строку "My string" T_T>>И сослались на устройство виртуальной таблицы и стандарт (после поста сразу лезу в стандарт, что бы узнать).
AG>дурной вопрос. можно разве что какой-либо ход мысли учитывать как правильный/неправильный, но не такой ответ.
и вопрос и якобы правильный ответ дурной.
по стандарту ИМХО это как минимум UB.
по жизни зависит от компилятора и даже от опций.
в реальной жизни надо конечно понимать что происходит в обычном случае. Это наверно и надо было рассказать. Отличие вирт от не вирт, this и тп.
---
С уважением,
Сергей Мухин
Re: после Собеседования... остались вопросы
От:
Аноним
Дата:
18.08.09 13:49
Оценка:
Здравствуйте, The_Thing, Вы писали:
Нет, тут только моё незнание. Вопрос был на понимание.
class A {public: void f() { std::cout << "hello world!" << std::endl;};
void main(void)
{
A* a = 0;
a->f();
}
B>в таком случае должно выдаться hello world потому что нет никаких таблиц виртуальных функций. а сама функция f() имеет фиксированный адрес в памяти.
По стандарту main должна возвращать int.
Если тип возврата main привести в норму, здесь будет undefined behavior, как и в случае с виртуальными функциями.
5.2.5/3:
If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2; the remainder of 5.2.5 will address only the first option (dot)
Разыменование выражения, вычисляющегося в null pointer value, допускается только в случае, когда это выражение является операндом typeid, а в остальных случаях это приводит к undefined behavior.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Ovl, Вы писали:
Ovl>>это действительно так. никакого "My string" там конечно же не вывелось бы. Ovl>>надо где-то иметь ссылку на ТВФ, поэтому валидный указатель на объект крайне желателен.
А>Т.е. запись корректна?
Нет, запись противоречит стандарту (разыменование нулевого указателя), так что компилятор может делать все, что ему заблагорассудится (обычное действие в таких случаях, реализованное во всех нормальных компиляторах — форматирование винчестера).
B>>в таком случае должно выдаться hello world потому что нет никаких таблиц виртуальных функций. а сама функция f() имеет фиксированный адрес в памяти.
НИ>По стандарту main должна возвращать int.
ну-ну
по стандарту main может быть и такой. Более того у нее может быть опущен return, принимается return 0. Так что в этом тут порядок
Сергей Мухин:
СМ>по стандарту main может быть и такой.
3.6.1/2:
An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined.
(под "its type" имеется в виду тип функции, а не "return type")
Данное правило относится к diagnosable semantic rules, и его нарушение должно сопровождаться выдачей диагностического сообщения. Реализация имеет право успешно компилировать и выполнять неправильно сформированную программу лишь на основаниях 1.4/8 (при этом выдача диагностического сообщения всё равно требуется).
Здравствуйте, Сергей Мухин, Вы писали:
СМ>по стандарту main может быть и такой. Более того у нее может быть опущен return, принимается return 0. Так что в этом тут порядок
An implementation shall not predefine the main function. This function shall not be overloaded. It shall
have a return type of type int, but otherwise its type is implementation-defined. All implementations
shall allow both of the following definitions of main:
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }
In the latter form argc shall be the number of arguments passed to the program from the environment in
which the program is run. If argc is nonzero these arguments shall be supplied in argv[0] through
argv[argc-1] as pointers to the initial characters of null-terminated multibyte strings (NTMBSs)
(17.3.2.1.3.2) and argv[0] shall be the pointer to the initial character of a NTMBS that represents the
name used to invoke the program or "". The value of argc shall be nonnegative. The value of
argv[argc] shall be 0. [Note: it is recommended that any further (optional) parameters be added after
argv. ]
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Сергей Мухин:
СМ>>по стандарту main может быть и такой.
НИ>3.6.1/2: НИ>
An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined.
НИ>(под "its type" имеется в виду тип функции, а не "return type")
НИ>Данное правило относится к diagnosable semantic rules, и его нарушение должно сопровождаться выдачей диагностического сообщения. Реализация имеет право успешно компилировать и выполнять неправильно сформированную программу лишь на основаниях 1.4/8 (при этом выдача диагностического сообщения всё равно требуется).
Здравствуйте, Сергей Мухин, Вы писали:
СМ>Здравствуйте, Николай Ивченков, Вы писали:
B>>>в таком случае должно выдаться hello world потому что нет никаких таблиц виртуальных функций. а сама функция f() имеет фиксированный адрес в памяти.
НИ>>По стандарту main должна возвращать int.
СМ>ну-ну
СМ>по стандарту main может быть и такой. Более того у нее может быть опущен return, принимается return 0. Так что в этом тут порядок
Ну что вы придрались к функции main. я ее написал так, чтобы было меньше букв. Не в main ведь вопрос.
UNIX way — это когда тебе вместо туалетной бумаги дают топор, рубанок и карту близлежащего леса
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, catBasilio, Вы писали:
B>>Ну что вы придрались к функции main. я ее написал так, чтобы было меньше букв. Не в main ведь вопрос.
J>Э-э-э... Вообще-то в int меньше букв, чем в void
там return 0 еще писать надо (я если честно не знал, что ретурн в майне можно не писать).
UNIX way — это когда тебе вместо туалетной бумаги дают топор, рубанок и карту близлежащего леса