Предполагается ли использование декларации скрыть унаследованную виртуальную функцию?
-
10-10-2019 - |
Вопрос
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;
}
Таким образом, один и тот же объект, когда используется непосредственно, дает разные результаты и при использовании через указатель того же типа дает разные результаты !!!
Решение
Пример в стандартном разделе 10.3p2 дает понять, что использование объявлений делает нет переопределить виртуальные функции.
Как вы заметили, при вызове функции элемента через ссылку или указатель, а не случай, когда динамический тип известен, ошибка не происходит.
Другие советы
using level1::foo;
представляет foo
функционировать в level3
класс, который относится к level1::foo
.
При использовании декларации, используемого в качестве декларации члена, вложенная имен-специфическая должна назвать базовый класс, определяемый классом. Такое использование декларации вводит набор объявлений, найденных по имени участника.
Однако, поскольку level1::foo
виртуально, я думаю, что, позвонив, вы должны позвонить level2::foo
, таким образом, ICC должен быть прав.
Я не уверен, в любом случае.
Способ получить уровень 1 уровня1, конечно, будет:
struct level3 : level2
{
virtual void foo() { level1::foo(); }
};
Ваша директива «Использование», кажется, информирует компилятора, что если у вас есть уровень 3 и вызовать Foo на ней, она должна вызывать версию Level1, но это не перезаписывает это на V-таблице.
GCC выглядит неправильно из -за несоответствия, не уверен в ICC, потому что я не знаю, что указывает стандарт.