struct A
{
virtual void fun(){}
};
struct B:virtual public A
{
void fun(){}
};
struct C:B, virtual A
{
using A::fun;
};
void foo()
{
C c;
c.fun();//Стандарт говорит, что здесь д.б. вызван final overrider
//это так? а то у меня вызывается A::fun.
}
Здравствуйте, Аноним, Вы писали:
А>Что за странный пример в 10.3/2
А>struct A
А>{
А> virtual void fun(){}
А>};
А>struct B:virtual public A
А>{
А> void fun(){}
А>};
А>struct C:B, virtual A
А>{
А> using A::fun;
А>};
А>void foo()
А>{
А> C c;
А> c.fun();//Стандарт говорит, что здесь д.б. вызван final overrider
А> //это так? а то у меня вызывается A::fun.
А>}
Из примера и утверждения в стандарте возникает впечатление, что наличие ключевого слова virtual должно модифицировать правила поиска имен. Т.е. если б fun была невиртуальной, то using — объявление не игнорировалось бы???? Объяснмите, плиз. Потом, если это правда, то как быть с ситуацией, если в базе есть две перегруженных fun одна вирт., другая нет???
Of course, the code must be complete enough to compile and link.
Здравствуйте, Аноним, Вы писали:
А>Что за странный пример в 10.3/2 А>[ccode] А>struct A А>{ А> virtual void fun(){} А>};
А>struct B:virtual public A А>{ А> void fun(){} А>};
А>struct C:B, virtual A А>{ А> using A::fun; А>};
А>void foo() А>{ А> C c; А> c.fun();//Стандарт говорит, что здесь д.б. вызван final overrider А> //это так? а то у меня вызывается A::fun. А>}
Гораздо смешнее этот пример выглядит если в foo добавить:
Здравствуйте, Romanch, Вы писали:
R>Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>>>Очередной баг в VC6 ?
L_L>>Что вызывается?
R>6-й вижуал
R>void foo()
R>{
R> C c;
R> A* pa = &c;
R> c.fun(); // Вот тут вызывается A::fun
pa->>fun(); // А вот тут B::fun - хехе, так на то и виртуальная функция. Здесь все
// правильно, это и есть final overrider
}
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Здравствуйте, Romanch, Вы писали:
R>>Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>>>>Очередной баг в VC6 ?
L_L>>>Что вызывается?
R>>6-й вижуал L_L>
R>>void foo()
R>>{
R>> C c;
R>> A* pa = &c;
R>> c.fun(); // Вот тут вызывается A::fun
L_L>
pa->>>fun(); // А вот тут B::fun - хехе, так на то и виртуальная функция. Здесь все
L_L>// правильно, это и есть final overrider
L_L>
L_L>}
L_L>
Угу, остается ответить на вопрос — почему c.fun() приводит к вызову другой функции.
То что компилятор в этом месте подавляет механизм виртуального вызова понятно, непонятно почему генерится прямой вызов A::fun вместо B::fun. Что-то я сомневаюсь, что так по стандарту положено.
IMHO объяснить это можно так — компилятор обрабатывает using A тупо добавляя A:: к каждому имени из этой области видимости. Например:
namespace A
{
void fun();
};
void f()
{
using namespace A;
fun(); // это место приводится к A::fun
}
Здравствуйте, Romanch, Вы писали:
R>Очередной баг в VC6 ?
GCC 3.2 подвержен этому "багу" в равной степени
Ситуация, на мой взгляд, такая:
struct A
{
virtual void fun() {}
};
struct B:virtual public A
{
void fun() {}
};
struct C:B, virtual A
{
using A::fun; // (0)
};
void foo()
{
C c;
c.fun(); // C::fun() == A::fun() (1)
A* p = &c;
p->fun(); // полиморфный вызов (2)
}
(0) — Функции, объявленные в в производном классе, скрывают функции из базового класса, которые в противном случае были бы доступны. Достигается using-объявлением.
(1) — Статический вызов C::A(). (0) Приводит к тому, что вызов с полностью квалифицированным именем C::fun() должен приводить к A::fun(). Все законно.
(2) — полиморфный вызов. вызывает последнюю определенную функцию для A::fun(), т.е. B::fun()
По моим представлениям, using-объявление — это объявление члена, потому оно скрывает fun из B и все правильно. В исходном примере в стандарте говорилось, что такие using объявления должны игнорироваться в случае вирт. функций! Вот в чем загвоздка! Кто нибудь, разъясните!
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>По моим представлениям, using-объявление — это объявление члена, потому оно скрывает fun из B и все правильно. В исходном примере в стандарте говорилось, что такие using объявления должны игнорироваться в случае вирт. функций! Вот в чем загвоздка! Кто нибудь, разъясните!
Естественно должны игнорироваться, т.к. виртуальная функция всегда должна вызываться из самого производного класса независимо от контекста вызова (явную спецификацию тут не рассматриваем, не тот случай).
А вот щас буит еще смешнее
#include <stdio.h>
struct A
{
virtual void fun(){ printf("A::f\n"); }
};
struct B:virtual public A
{
virtual void fun(){ printf("B::f\n"); }
};
struct C:B, virtual A
{
using A::fun;
};
void g(C* pc)
{
pc->fun();
}
void main()
{
C c;
A* pa = &c;
c.fun(); // A::fun
g(&c); // B::fun
pa->fun(); // B::fun
}
Настораживает только то, что и VC6, и VC7.1 (на gcc попробуйте кто-нить, плиз) понимают это одинаково. Может все-таки это я чего не догоняю ?
Здравствуйте, Kaa, Вы писали:
Kaa>(0) — Функции, объявленные в в производном классе, скрывают функции из базового класса, которые в противном случае были бы доступны. Достигается using-объявлением. Kaa>(1) — Статический вызов C::A(). (0) Приводит к тому, что вызов с полностью квалифицированным именем C::fun() должен приводить к A::fun(). Все законно. Kaa>(2) — полиморфный вызов. вызывает последнюю определенную функцию для A::fun(), т.е. B::fun()
Это все, конечно, верно, но вызов c.fun() это тоже полиморфный вызов. В том что c.C::fun() должно вызывать A::fun никто и не сомневается.
R>Естественно должны игнорироваться, т.к. виртуальная функция всегда должна вызываться из самого производного класса независимо от контекста вызова (явную спецификацию тут не рассматриваем, не тот случай).
Не спеши насчет естественно. В примере — откровенно неполиморфный вызов C c; c.fun(); и стандарт утверждает, что игнорируется using — объявление — стало быть в примере глюк.
R>А вот щас буит еще смешнее R>Настораживает только то, что и VC6, и VC7.1 (на gcc попробуйте кто-нить, плиз) понимают это одинаково. Может все-таки это я чего не догоняю ?
Действительно не совсем догоняешь. При вызове через ссылки и указатели используется механизм вызова виртуальных функций и тут уж все точно ок.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
LL>В исходном примере в стандарте говорилось, что такие using объявления должны игнорироваться в случае вирт. функций! Вот в чем загвоздка!
Ну укажи этот пример. Я вот вижу 7.3.3/12, в котором все достаточно доступно: имя из базового класса, введенное using-декларацией, будет скрыто в производном классе переопределением функции с той же сигнатурой, что и в базовом. Покуда переопределения не случилось, ничего никуда не скрывается. И ни слова про исключение для случая с виртуальными функциями.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Здравствуйте, Romanch, Вы писали:
R>>Это все, конечно, верно, но вызов c.fun() это тоже полиморфный вызов.
L_L>Нет, это неполиморфный вызов
Т.е. ты утверждаешь, что в контексте нашего примера c.fun() и c.C::fun() одно и то же ?
Хммм... придется лезть в стандарт.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Динамическое связывание работает только при использовании ссылок и указателей. В случае с L_L>C c; c.fun(); нужная функция известна на этапе компиляции.
Ладно, тогда я задам другой вопрос — c.fun() и (&c)->fun() одно и то же ?
Кстати, 6й и 7й вижуалы в последнем случае тоже вызывают A::fun
Пункт 10.3 о том и говорит, что даже при вызове виртуальной функции НЕ через указатель, поведение программы должно быть таким, как будто функцию вызвали ЧЕРЕЗ указатель. Собственно, стандарту в этом месте пофиг как вызывают виртуальную ф-ю, для конкретного класса есть единственный final overrider, он и должен вызываться, это и есть полиморфный вызов. А уж как компилятор это реализует в конкретном случае, с использованием таблицы виртуальных функций или без оного, не суть важно.
Вывод, следовательно, такой — и вижуал и gcc на этом примере глючат. Про другие компиляторы кто-нить может рассказать ?
Здравствуйте, Аноним, Вы писали:
А>Что за странный пример в 10.3/2
так написано же: using игнорируются при вызове виртуальной функции.
а при вызове с полной квалификацией виртуальный механизм подавляется.
Пример абсолютно корректен.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Аноним, Вы писали:
А>>Что за странный пример в 10.3/2
J>так написано же: using игнорируются при вызове виртуальной функции. J>а при вызове с полной квалификацией виртуальный механизм подавляется. J>Пример абсолютно корректен.
Да??? А вот это C c; c.fun()?
А как быть если есть fun и виртуальная и не виртуальная? А если не виртуальная, то не игнорируется?
Я считаю пример некорректным
Of course, the code must be complete enough to compile and link.