Здравствуйте, jazzer, Вы писали:
J>так написано же: using игнорируются при вызове виртуальной функции. J>а при вызове с полной квалификацией виртуальный механизм подавляется. J>Пример абсолютно корректен.
(шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Здравствуйте, jazzer, Вы писали:
J>>Здравствуйте, Аноним, Вы писали:
А>>>Что за странный пример в 10.3/2
J>>так написано же: using игнорируются при вызове виртуальной функции. J>>а при вызове с полной квалификацией виртуальный механизм подавляется. J>>Пример абсолютно корректен.
L_L>Да??? А вот это C c; c.fun()? L_L>А как быть если есть fun и виртуальная и не виртуальная? А если не виртуальная, то не игнорируется? L_L>Я считаю пример некорректным
А где тут виртуальные и невиртуальные???
я вижу только одну виртуальную функцию, объявленную в А и перекрытую в B.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
А>>>Что за странный пример в 10.3/2
J>>так написано же: using игнорируются при вызове виртуальной функции. J>>а при вызове с полной квалификацией виртуальный механизм подавляется. J>>Пример абсолютно корректен.
L_L>Да??? А вот это C c; c.fun()? L_L>А как быть если есть fun и виртуальная и не виртуальная? А если не виртуальная, то не игнорируется?
Угу, именно так и должно быть, для виртуальных функций using игнорируется, для невиртуальных (а так же виртуальных, но вызванных с явным спецификатором области видимости) используется using.
L_L>Я считаю пример некорректным
А я считаю некорректым поведение компиляторов на этом примере.
Компилируя вызов c.fun() компилятор в общем случае ОБЯЗАН воспользоваться таблицей виртуальных функций, именно такое его поведение приведет к игнорированию using для этой конкретной функции. Другое дело, что он МОЖЕТ соптимизировать вызов, зная, что 'С' это most derived класс, компилятор может сгенерить прямой вызов final overrider'а, но уж ни в коем случае не функции объявленной через using. Про это, кажется, в ARM от старой версии C++ было написано, не думаю, что стандарт мог так радикально поменяться.
Здравствуйте, Kaa, Вы писали:
J>>так написано же: using игнорируются при вызове виртуальной функции. J>>а при вызове с полной квалификацией виртуальный механизм подавляется. J>>Пример абсолютно корректен.
Kaa>(шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте
(тоже шепотом) А иначе некорректен пример приведенный в стандарте языка
Вопрос что впереди, телега или лошадь ?
Здравствуйте, Kaa, Вы писали:
Kaa>(0) — Функции, объявленные в в производном классе, скрывают функции из базового класса, которые в противном случае были бы доступны. Достигается using-объявлением.
Это неверно для виртуальных функций. Да и вообще формулировка нехорошая, можно долго и разнообразно придираться :)
R>Компилируя вызов c.fun() компилятор в общем случае ОБЯЗАН воспользоваться таблицей виртуальных функций, именно такое его поведение приведет к игнорированию using для этой конкретной функции. Другое дело, что он МОЖЕТ соптимизировать вызов, зная, что 'С' это most derived класс, компилятор может сгенерить прямой вызов final overrider'а, но уж ни в коем случае не функции объявленной через using. Про это, кажется, в ARM от старой версии C++ было написано, не думаю, что стандарт мог так радикально поменяться.
Именно это и написано в Стандарте прямо над цитируемым примером. (Правда, там не упоминается вмт :) )
Здравствуйте, Romanch, Вы писали:
R>Здравствуйте, Kaa, Вы писали:
J>>>так написано же: using игнорируются при вызове виртуальной функции. J>>>а при вызове с полной квалификацией виртуальный механизм подавляется. J>>>Пример абсолютно корректен.
Kaa>>(шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте :)
R>(тоже шепотом) А иначе некорректен пример приведенный в стандарте языка :) R>Вопрос что впереди, телега или лошадь ? :)
нормативная часть Стандарта впереди примеров, которые являются лишь иллюстрациями.
Но в данном случае я не вижу противоречия примера нормативной части.
Здравствуйте, jazzer, Вы писали:
R>>Компилируя вызов c.fun() компилятор в общем случае ОБЯЗАН воспользоваться таблицей виртуальных функций, именно такое его поведение приведет к игнорированию using для этой конкретной функции. Другое дело, что он МОЖЕТ соптимизировать вызов, зная, что 'С' это most derived класс, компилятор может сгенерить прямой вызов final overrider'а, но уж ни в коем случае не функции объявленной через using. Про это, кажется, в ARM от старой версии C++ было написано, не думаю, что стандарт мог так радикально поменяться.
J>Именно это и написано в Стандарте прямо над цитируемым примером. (Правда, там не упоминается вмт )
Во ! Золотые слова !
Но проблема в том, что 3 (три!) компилятора, VC6, VC7 и g++, неправильно компилируют этот пример. Там, где в стандарте написано
...
c.f(); // calls B::f(), the final overrider
...
Здравствуйте, Lorenzo_LAMAS, Вы писали:
А>> Что за странный пример в 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.
А>> }
А>>
LL> Из примера и утверждения в стандарте возникает впечатление, что наличие LL> ключевого слова virtual должно модифицировать правила поиска имен.
Так и есть.
The rules for member lookup (10.2) are used to determine the final overrider for a virtual
function in the scope of a derived class but ignoring names introduced by using-declarations.
LL> Т.е. если б fun была невиртуальной, то using — объявление не игнорировалось бы????
Да. Если бы функция fun была бы невиртуальной, в обоих случаях была бы вызвана A::fun,
т.к. это явно указано путем использования using-declaration.
LL> Объяснмите, плиз.
А что тут объяснять-то? Если бы не было специального правила для виртуальных функций, получалось
бы, то, что наблюдается в старых версиях VC и в GCC: "виртуальные невиртуальные функции".
LL> Потом, если это правда, то как быть с ситуацией, если в базе LL> есть две перегруженных fun одна вирт., другая нет???
Соответственно:
#include <iostream>
struct A
{
virtual void fun(int) { std::cout << "A::fun(int)" << std::endl; }
void fun(float) { std::cout << "A::fun(float)" << std::endl; }
};
struct B : virtual A
{
void fun(int) { std::cout << "B::fun(int)" << std::endl; }
void fun(float) { std::cout << "B::fun(float)" << std::endl; }
};
struct C : B, virtual A
{
using A::fun;
};
int main()
{
C c;
c.fun(10); // B::fun(int)
c.fun(1.0f); // A::fun(float)
A* p = &c;
p->fun(10); // B::fun(int)
p->fun(1.0f); // A::fun(float)
}
> como main_nv.cpp
Comeau C/C++ 4.3.0.1 (Aug 21 2002 15:45:32) for MS_WINDOWS_x86
Copyright 1988-2002 Comeau Computing. All rights reserved.
MODE:strict warnings C++
> aout
B::fun(int)
A::fun(float)
B::fun(int)
A::fun(float)
> cl /GX main_nv.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
main_nv.cpp
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main_nv.exe
main_nv.obj
> main_nv
B::fun(int)
A::fun(float)
B::fun(int)
A::fun(float)
> bcc32 main_nv.cpp
Borland C++ 5.6 for Win32 Copyright (c) 1993, 2002 Borland
main_nv.cpp:
Turbo Incremental Link 5.60 Copyright (c) 1997-2002 Borland
> main_nv
B::fun(int)
A::fun(float)
B::fun(int)
A::fun(float)
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Kaa, Вы писали:
J>> так написано же: using игнорируются при вызове виртуальной функции.
K> (шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте
Да, некорректна. Для успокоения: Visual 7.1, Borland 5.6 и (last but not least) Comeau
работают в этом случае, как указано в примере в стандарте.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Kaa, Вы писали:
K> (1) — Статический вызов C::A(). (0) Приводит к тому, что вызов с полностью K> квалифицированным именем C::fun() должен приводить к A::fun(). Все законно.
С той только разницей, что т.к. функция виртуальна, результаты должны быть такие же, как и в (2).
K> (2) — полиморфный вызов. вызывает последнюю определенную функцию для A::fun(), т.е. B::fun()
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
R> Настораживает только то, что и VC6, и VC7.1 <...> понимают это одинаково.
Ты ничего не перепутал? Именно VC7.1? У меня VC7.1 выдает то, что и ожидается:
> cl main2.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
main2.cpp
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main2.exe
main2.obj
> main2
B::f
B::f
B::f
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>> Естественно должны игнорироваться, т.к. виртуальная функция всегда должна R>> вызываться из самого производного класса независимо от контекста вызова
LL> Не спеши насчет естественно. В примере — откровенно неполиморфный вызов C c; c.fun();
Тем не меннее, компилятор обязан вызвать fun из наиболее унаследованного объекта.
Стандарт не дает никакой специальной свободы компилятору в случае неполиморфного вызова.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
R>> Настораживает только то, что и VC6, и VC7.1 <...> понимают это одинаково.
ПК>Ты ничего не перепутал? Именно VC7.1? У меня VC7.1 выдает то, что и ожидается:
ПК>
>> cl main2.cpp
ПК>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
ПК>Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
ПК>main2.cpp
ПК>Microsoft (R) Incremental Linker Version 7.10.3077
ПК>Copyright (C) Microsoft Corporation. All rights reserved.
ПК>/out:main2.exe
ПК>main2.obj
>> main2
ПК>B::f
ПК>B::f
ПК>B::f
ПК>
Угу, сори, таки перепутал, то 7.0 был. 7.1 действительно все компилит правильно.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
LL> Кажется начинаю догонять Получается, что виртуальные функции всегда, LL> даже в случае неполиморфного вызова должны вести себя как виртуальные?
Да. Исключение составляет вызов с явным указанием класса, чью функцию нужно вызывать.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Облазив весь группогуголь и стандарт, выяснил, что мне показалось неправильно. Однако то, что новий GCC (3.2) выдал результат, аналогичный VC6 98-го года выпуска, меня несколько смутило.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Кажется начинаю догонять L_L>Получается, что виртуальные функции всегда, даже в случае неполиморфного вызова должны вести себя как виртуальные?
Нет такого понятия — неполиморфный вызов.
Есть просто вызов (всегда полиморфный для виртуальной функции) и вызов с явной квалификацией (при этом нет вообще понятия "виртуальный" — так написано в Стандарте).
Если ты понимаешь под неполиморфным вызовом вызов без runtime-обращения к vmt, то никто не мешает компилятору сгенерить явный вызов final overrider-a, если ему и так понятно, что именно надо звать (а в обсуждаемом примере именно эта ситуация и есть).
Но это лишь вопрос оптимизации, не более. Идеологически правильно считать, что при отсутствии явной квалификации вызов всегда идет через vmt.
А что там наоптимизирует компилятор — дело десятое, хотя и полезное
Здравствуйте, jazzer, Вы писали:
j> Нет такого понятия — неполиморфный вызов.
Зато есть понятие virtual function call, или, в некоторых местах, virtual call.
j> Есть просто вызов (всегда полиморфный для виртуальной функции) и вызов с явной j> квалификацией (при этом нет вообще понятия "виртуальный" — так написано в Стандарте).
Ну почему же? В стандарте написано, что явная квалификация подавляет механизм виртуального вызова:
10.3 Explicit qualification with the scope operator (5.1) suppresses the virtual call mechanism.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен