Re[2]: final overrider
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 19.06.03 14:10
Оценка:
Здравствуйте, jazzer, Вы писали:

J>так написано же: using игнорируются при вызове виртуальной функции.

J>а при вызове с полной квалификацией виртуальный механизм подавляется.
J>Пример абсолютно корректен.

(шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте
Алексей Кирдин
Re[3]: final overrider
От: jazzer Россия Skype: enerjazzer
Дата: 19.06.03 14:29
Оценка:
Здравствуйте, 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.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: final overrider
От: Romanch  
Дата: 19.06.03 14:35
Оценка:
Здравствуйте, 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++ было написано, не думаю, что стандарт мог так радикально поменяться.
Re[3]: final overrider
От: Romanch  
Дата: 19.06.03 14:37
Оценка:
Здравствуйте, Kaa, Вы писали:

J>>так написано же: using игнорируются при вызове виртуальной функции.

J>>а при вызове с полной квалификацией виртуальный механизм подавляется.
J>>Пример абсолютно корректен.

Kaa>(шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте


(тоже шепотом) А иначе некорректен пример приведенный в стандарте языка
Вопрос что впереди, телега или лошадь ?
Re[3]: final overrider
От: jazzer Россия Skype: enerjazzer
Дата: 19.06.03 14:41
Оценка:
Здравствуйте, Kaa, Вы писали:

Kaa>(0) — Функции, объявленные в в производном классе, скрывают функции из базового класса, которые в противном случае были бы доступны. Достигается using-объявлением.


Это неверно для виртуальных функций. Да и вообще формулировка нехорошая, можно долго и разнообразно придираться :)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: final overrider
От: jazzer Россия Skype: enerjazzer
Дата: 19.06.03 14:43
Оценка:
Здравствуйте, Romanch, Вы писали:



R>Компилируя вызов c.fun() компилятор в общем случае ОБЯЗАН воспользоваться таблицей виртуальных функций, именно такое его поведение приведет к игнорированию using для этой конкретной функции. Другое дело, что он МОЖЕТ соптимизировать вызов, зная, что 'С' это most derived класс, компилятор может сгенерить прямой вызов final overrider'а, но уж ни в коем случае не функции объявленной через using. Про это, кажется, в ARM от старой версии C++ было написано, не думаю, что стандарт мог так радикально поменяться.


Именно это и написано в Стандарте прямо над цитируемым примером. (Правда, там не упоминается вмт :) )
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: final overrider
От: jazzer Россия Skype: enerjazzer
Дата: 19.06.03 14:45
Оценка:
Здравствуйте, Romanch, Вы писали:

R>Здравствуйте, Kaa, Вы писали:


J>>>так написано же: using игнорируются при вызове виртуальной функции.

J>>>а при вызове с полной квалификацией виртуальный механизм подавляется.
J>>>Пример абсолютно корректен.

Kaa>>(шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте :)


R>(тоже шепотом) А иначе некорректен пример приведенный в стандарте языка :)

R>Вопрос что впереди, телега или лошадь ? :)

нормативная часть Стандарта впереди примеров, которые являются лишь иллюстрациями.
Но в данном случае я не вижу противоречия примера нормативной части.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: final overrider
От: Romanch  
Дата: 19.06.03 14:56
Оценка:
Здравствуйте, 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
...


вызывается почему-то A::f()
Re[2]: final overrider
От: Павел Кузнецов  
Дата: 19.06.03 15:48
Оценка: 3 (1)
Здравствуйте, 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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: final overrider
От: Павел Кузнецов  
Дата: 19.06.03 16:00
Оценка:
Здравствуйте, Kaa, Вы писали:

J>> так написано же: using игнорируются при вызове виртуальной функции.


K> (шепотом) Тогда некорректна работа как минимум 3-х компиляторов в этом месте


Да, некорректна. Для успокоения: Visual 7.1, Borland 5.6 и (last but not least) Comeau
работают в этом случае, как указано в примере в стандарте.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: final overrider
От: Павел Кузнецов  
Дата: 19.06.03 16:00
Оценка:
Здравствуйте, 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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[8]: final overrider
От: Павел Кузнецов  
Дата: 19.06.03 16:00
Оценка:
Здравствуйте, Romanch, Вы писали:

R>
R> #include <stdio.h>
R> struct A
R> {
R>    virtual void fun(){ printf("A::f\n"); }
R> };

R> struct B:virtual public A
R> {
R>    virtual void fun(){ printf("B::f\n"); }
R> };

R> struct C:B, virtual A
R> {
R>     using A::fun;
R> };

R> void g(C* pc)
R> {
R>  pc->fun();
R> }

R> void main()
R> {
R>    C c;
R>    A* pa = &c;
R>    c.fun();    // A::fun
R>    g(&c);      // B::fun
R>    pa->fun();  // B::fun
R> }
R>


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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[9]: final overrider
От: Павел Кузнецов  
Дата: 19.06.03 16:07
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

R>> Естественно должны игнорироваться, т.к. виртуальная функция всегда должна

R>> вызываться из самого производного класса независимо от контекста вызова

LL> Не спеши насчет естественно. В примере — откровенно неполиморфный вызов C c; c.fun();


Тем не меннее, компилятор обязан вызвать fun из наиболее унаследованного объекта.
Стандарт не дает никакой специальной свободы компилятору в случае неполиморфного вызова.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[9]: final overrider
От: Romanch  
Дата: 19.06.03 16:24
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:


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 действительно все компилит правильно.
Re[3]: final overrider
От: Lorenzo_LAMAS  
Дата: 20.06.03 07:05
Оценка:
Кажется начинаю догонять
Получается, что виртуальные функции всегда, даже в случае неполиморфного вызова должны вести себя как виртуальные?
Of course, the code must be complete enough to compile and link.
Re[4]: final overrider
От: Павел Кузнецов  
Дата: 20.06.03 07:36
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

LL> Кажется начинаю догонять Получается, что виртуальные функции всегда,

LL> даже в случае неполиморфного вызова должны вести себя как виртуальные?

Да. Исключение составляет вызов с явным указанием класса, чью функцию нужно вызывать.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: final overrider
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 20.06.03 08:45
Оценка:
Здравствуйте, Kaa, Вы писали:

Облазив весь группогуголь и стандарт, выяснил, что мне показалось неправильно. Однако то, что новий GCC (3.2) выдал результат, аналогичный VC6 98-го года выпуска, меня несколько смутило.

Мое предыщущее сообщение считать неверным.
Алексей Кирдин
Re[4]: final overrider
От: Lorenzo_LAMAS  
Дата: 20.06.03 08:50
Оценка:
Kaa>Однако то, что новий GCC (3.2) выдал результат, аналогичный VC6 98-го года выпуска, меня несколько смутило.

На то он и бесплатный
Of course, the code must be complete enough to compile and link.
Re[4]: final overrider
От: jazzer Россия Skype: enerjazzer
Дата: 20.06.03 08:58
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Кажется начинаю догонять

L_L>Получается, что виртуальные функции всегда, даже в случае неполиморфного вызова должны вести себя как виртуальные?

Нет такого понятия — неполиморфный вызов.
Есть просто вызов (всегда полиморфный для виртуальной функции) и вызов с явной квалификацией (при этом нет вообще понятия "виртуальный" — так написано в Стандарте).

Если ты понимаешь под неполиморфным вызовом вызов без runtime-обращения к vmt, то никто не мешает компилятору сгенерить явный вызов final overrider-a, если ему и так понятно, что именно надо звать (а в обсуждаемом примере именно эта ситуация и есть).

Но это лишь вопрос оптимизации, не более. Идеологически правильно считать, что при отсутствии явной квалификации вызов всегда идет через vmt.

А что там наоптимизирует компилятор — дело десятое, хотя и полезное
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: final overrider
От: Павел Кузнецов  
Дата: 20.06.03 09:33
Оценка:
Здравствуйте, 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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.