C++ Inheritance via Dominance Warning

C++ Inheritance via dominance warning

Everything is absolutely valid. A compiler is allowed to warn about valid code, no problem here. You can try silencing the warning with a using declaration. If this doesn't work (probably due to an MSVC bug), silence it with a pragma.

Inheritance by dominance - is it really bad?

When performing virtual inheritance, it is a bad idea to not explicitly override every member in the most derived class. Else, you are asking for your code to die a horrible death when someone changes one of your base classes that inherits from the virtual base. There's nothing actively wrong with this, your program won't crash or anysuch, but it's a maintainability bad idea. If you want to call the Bar::foo version, then you should just delegate to it in Quux::foo.

Avoiding an inheritance by dominance warning for a mocked std::fstream class

It turns out that these warnings are a side-effect from some quirks in the Microsoft C++ STL. I've quoted an explanation from the relevant Microsoft Connect issue below.

My solution was simply to implement empty versions of the inherited functions in my mock:

TEST_F(SomeTest, SomethingIsDoneCorrectly)
{
class MockFstream : public std::fstream
{
void _Add_vtordisp1() { } // Required to avoid VC++ warning C4250
void _Add_vtordisp2() { } // Required to avoid VC++ warning C4250
};
MockFstream lMockFstream;
// Expectations and assertions here
}

An explanation from Microsoft about why the warning occurs:

The story here is somewhat complicated. VC has an obscure compiler option, /vd2 (documented at http://msdn.microsoft.com/en-us/library/7sf3txa8.aspx), that fixes an obscure bug involving virtual base classes. By default, VC does something that's slightly nonconformant to the C++ Standard. /vd2 changes VC's behavior to be conformant, but this inherently affects class layout. (This layout difference is why the default hasn't been changed to be conformant - that would break users attempting to mix code compiled with different major versions of VC. Our C++ Standard Library implementation forbids such mixing, but the compiler itself is somewhat more permissive.) So if users want /vd2, they have to compile everything that way.

The twist is that the layout bug (which /vd2 fixes) affects iostreams, which uses virtual base classes, and our iostreams implementation has a separately compiled component (in msvcp100.dll/libcpmt.lib/etc.). When MS builds the STL's DLL/LIB, they're compiled the default way, without /vd2. As a result, people using /vd2 couldn't use iostreams, or they'd get bizarre crashes. Yuck.

So, we added the do-nothing virtual functions _Add_vtordisp1() and _Add_vtordisp2(). Their presence makes VC perform layout completely conformantly, regardless of /vd2 being used or not, and therefore makes iostreams usable both ways.

_Add_vtordisp1() and _Add_vtordisp2() trigger warning C4250, talking about dominance. This warning is actually completely useless - it's saying that the compiler will do exactly what the Standard requires it to do. Therefore, we suppress it in the STL's headers (which must be /W4 /analyze clean). If you're deriving from fstream, you'll need to suppress this warning in your own code.

Visual Studio Compiler warning C4250 ('class1' : inherits 'class2::member' via dominance)

I had the same warning for the following code:

class Interface
{
public:
virtual void A() = 0;
};

class Implementation : public virtual Interface
{
public:
virtual void A() {};
};

class ExtendedInterface : public virtual Interface
{
virtual void B() = 0;
};

class ExtendedImplementation : public ExtendedInterface , public Implementation
{
public:
virtual void B() {};
};

This bug report for Visual C++ 2005 in msdn suggests that this is a known bug that was considered not important enough to fix... They suggest to disable the warning in this case by using a pragma. I think it is safe also in your case, but you should use virtual inheritance as shown in the answer by Gal Goldman.

What causes C4250 (class inherits member via dominance) when using boost serialization with a virtual base class?

The reason is in fact the is_virtual_base_of check from boost type traits. This check-construct will generate warning C4250 if the check is successful, as can be seen by this example:

...
struct base {
virtual void mf() { };
};
struct derived_normal : public base {
virtual void mf() { };
};
struct derived_virt : virtual public base {
virtual void mf() { };
};

int main() {
using namespace std;

cout << "boost::is_virtual_base_of<base, derived_normal>::value reports: ";
// The following line DOES NOT cause C4250
cout << boost::is_virtual_base_of<base, derived_normal>::value << endl;

cout << "boost::is_virtual_base_of<base, derived_virt> reports: ";
// The following line causes C4250:
cout << boost::is_virtual_base_of<base, derived_virt>::value << endl;
...

FWIW, the usage of this type-traits tool in boost serialization goes like this:

  • macro BOOST_EXPORT_CLASS ->
    • macro BOOST_CLASS_EXPORT_IMPLEMENT ->
      • struct guid_initializer (in export.hpp) ->
      • (...) void_cast.hpp / void_cast_register -> is_virtual_base_of is used here

As far as I can tell the warning is completely harmless in this case and can be prevented by wrapping the header in:

#pragma warning( push )
#pragma warning( disable : 4250 ) // C4250 - 'class1' : inherits 'class2::member' via dominance
#include ...
#pragma warning( pop ) // C4250

What does C4250 VC++ warning mean?

The warning is pointing out that if any weak class operations depend on vbc virtual operations that are implemented in dominant, then those operations might change behavior due to the fact that they are bundled in a diamond inheritance hierarchy.

struct base {
virtual int number() { return 0; }
};
struct weak : public virtual base {
void print() { // seems to only depend on base, but depends on dominant
std::cout << number() << std::endl;
}
};
struct dominant : public virtual base {
int number() { return 5; }
};
struct derived : public weak, public dominant {}

int main() {
weak w; w.print(); // 0
derived d; d.print(); // 5
}

That is the behavior that the standard specifies, but it might be surprising for the programmer at times, the weak::print operation behavior has changed not because of an overridden method above or below in the hierarchy, but by a sibling class in the inheritance hierarchy, when called from derived. Note that it makes perfect sense from the derived point of view, it is calling an operation that depends on a virtual method implemented in dominant.

Diamond-inheritance scenario compiles fine in G++, but produces warnings/errors in VC++/Eclipse

What is the correct way of doing this? Does the code above produce undefined behavior?

The code is perfectly valid. There is no Undefined Behavior here.

An unqualified call of A() through a DerivedC class object, will always call DerivedA::A(), while an unqualified call of B() through a DerivedC class object, will always call the DerivedB::B() instance.

Visual C++ gives you a warning because your code uses a less commonly known feature of virtual Inheritance which may not be obvious to most common users and might surprise them. In this case, the warning should be taken as an Informative Nitpick rather than a warning.

Note that the C++ Standard does not restrict compilers from emitting informative warnings for perfectly valid code.
The documentation for warning C4250 gives an example which tells you why visual C++ chooses to give this warning.



Related Topics



Leave a reply



Submit