What is dominance in the context of virtual functions?
Asked Answered
M

1

6

Code Sample:

Consider the following diamond hierarchy:

struct A
{
    virtual void f(){}
    void g(){}
};    
struct B : virtual A
{
    virtual void f() override{}
    void g(){}
};     
struct C : virtual A
{   
};    
struct D: B, C
{    
};

int main()
{
    D d;
    d.f(); //B::f is called
    d.g(); //B::g is called
}

What I Do Understand:

As far as the non-virtual function g is concerned, everything is clear: the name B::g hides A::g, even though the name A::g could be reached without being hidden through C. There is no ambiguity. B::g is called. The standard explicitly confirms this in 10.2 p.10:

[ Note: When virtual base classes are used, a hidden declaration can be reached along a path through the subobject lattice that does not pass through the hiding declaration. This is not an ambiguity. The identical use with non-virtual base classes is an ambiguity; in that case there is no unique instance of the name that hides all the others. — end note ] [Example:

Additionally, this answer to a related question provided an exhaustive explanation of the issue.

The Problem:

What I don't understand is how the quote mentioned above pertains to the virtual function f. There is no name hiding involved with f, is there? Only overriding is involved, and 10.3 p.2 reads:

A virtual member function C::vf of a class object S is a final overrider unless the most derived class (1.8) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

Now, it seems to me, that the virtual function f exactly fits the definition of not having a final overrider and the program should be ill-formed. But it's not. Or is it? MSVC compiles it just fine, with the following warning:

warning C4250: 'D' : inherits 'B::B::f' via dominance

To be honest, I had never come across the term "dominance" before. When I search it in the standard, it has a single occurrence, in the index, and refers me to the chapter where my first quote comes from. And, as I already mentioned, the quote seems to pertain only to name hiding rather than virtual function overriding.

Questions:

  • Does f have more than one final overrider in D?
  • Does the rule of dominance apply in this case? How does it follow from the standard?
Mum answered 10/11, 2014 at 22:49 Comment(0)
A
5

I'll quote [10.3]/2 again:

A virtual member function C::vf of a class object S is a final overrider unless the most derived class (1.8) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

So in your example A::f is not a final overrider, because D (the most derived class) inherits B::f which overrides it. B::f is a final overrider, and so it is called.

The program would be ill-formed if there were more than one final overrider (for example if C also overrode f), but there is only one, so everything is fine.

Clang and GCC compile this without a single warning.

Answering your question, the documentation on C4250 warning describes exactly your situation, and by dominance it apparently means the behavior described in [10.3]/2.

Amero answered 10/11, 2014 at 23:7 Comment(6)
What is C::f() called? - it doesn't count as a virtual member function? (being inherited from A)Mopey
@MattMcNabb I don't understand the question. Class C doesn't override f.Amero
You can call C::f(), C inherits it from A without overridingMopey
@MattMcNabb So you mean D d; d.C::f();? Yes it will call A::f() according to 5.2.2/1 (it's found by usual overload resolution rules)Amero
@MattMcNabb: There is no function C::f but looking up f in the scope of C finds A::f. There's a subtle distinction in C++ between a scope containing foo and being able to find foo in that scope.Atlantis
@MattMcNabb "What is C::f() called?" C::f is A::f and is called a hidden name in DUndercut

© 2022 - 2024 — McMap. All rights reserved.