Ist eine using-Deklaration soll eine geerbte virtuelle Funktion verbergen?
-
10-10-2019 - |
Frage
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;
}
Der obige Code gcc gibt
level2
level1
aber in icc gibt
level2
level2
Welches ist richtig, oder ist es nicht definiert durch Standard?
Edit: Dies beweist, gibt es einen Fehler sicher, betrachten die folgende Hauptfunktion
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;
}
So das gleiche Objekt, wenn direkt verwendet unterschiedliche Ergebnisse, und wenn über einen Zeiger gleichen Typs verwendet zu unterschiedlichen Ergebnissen !!!
Lösung
An example in Standard section 10.3p2 makes it clear that using declarations do not override virtual functions.
This is a known g++ bug.
As you noticed, when calling the member function via a reference or pointer, rather than a case in which the dynamic type is known, the bug does not happen.
Andere Tipps
using level1::foo;
introduces a foo
function in level3
class which refers to level1::foo
.
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined. Such a using-declaration introduces the set of declarations found by member name lookup.
However, since level1::foo
is virtual, I guess that by calling it you should call level2::foo
, thus icc should be right.
I'm not so sure, anyway.
The way to get level1 level1 of course would be:
struct level3 : level2
{
virtual void foo() { level1::foo(); }
};
Your "using" directive seems to be informing the compiler that if you have a level3 and call foo on it, it should invoke the level1 version, but it is not overwriting this to the v-table.
gcc looks wrong because of the inconsistency, not sure about icc because I don't know what the standard indicates.