Должно ли объявление использования скрывать унаследованную виртуальную функцию?
struct level0
{
virtual void foo() = 0;
};
struct level1 : level0
{
virtual void foo() { cout <<" level1 " << endl; }
};
struct level2 : level1
{
virtual void foo() { cout <<" level2 " << endl; }
};
struct level3 : level2
{
using level1::foo;
};
int main()
{
level1* l1 = new level3;
l1->foo();
level3 l3;
l3.foo();
return 0;
}
приведенный выше код с использованием gcc дает
level2
level1
но в icc дает
level2
level2
Какой из них правильный или он не определен стандартом?
Изменить: Это доказывает, что есть ошибка, рассмотрим следующую основную функцию
int main()
{
level3 l3;
l3.foo(); // This prints level1
level3* pl3 = &l3;
pl3->foo(); // This prints level2
level3& rl3 = l3;
rl3.foo(); // This prints level1
level3& rpl3 = *pl3;
rpl3.foo(); // This prints level2
return 0;
}
Таким образом, один и тот же объект при непосредственном использовании дает разные результаты, а при использовании через указатель одного типа дает разные результаты!!!
3 ответа
Пример в разделе Standard 10.3p2 проясняет, что использование объявлений не переопределяет виртуальные функции.
Как вы заметили, при вызове функции-члена через ссылку или указатель, а не в случае, когда динамический тип известен, ошибка не возникает.
using level1::foo;
вводит foo
функция в level3
класс, который относится к level1::foo
,
В объявлении использования, используемом в качестве объявления члена, спецификатор nested-name должен указывать базовый класс определяемого класса. Такое объявление использования представляет набор объявлений, найденных при поиске имени члена.
Тем не менее, так как level1::foo
Виртуально, я думаю, что позвонив, вы должны позвонить level2::foo
Таким образом, ICC должен быть прав.
Во всяком случае, я не уверен
Конечно, способ получить level1 level1:
struct level3 : level2
{
virtual void foo() { level1::foo(); }
};
Ваша директива "using", кажется, сообщает компилятору, что если у вас есть level3 и вы вызываете foo для него, он должен вызвать версию level1, но он не переписывает это в v-таблицу.
GCC выглядит неправильно из-за несоответствия, не уверен насчет ICC, потому что я не знаю, что указывает стандарт.