Visual Studio Compiler Warning C4250 ('Class1':Inherits 'Class2::Member' via Dominance)

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.

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

Virtual inheritance and delegated implementation

This problem has been discussed previously. Dani van der Meer's answer specifically addresses this issue. It's been filed as a won't fix bug report in Visual Studio since 2005.

If you're not a fan of disabling warnings, you could always make the function selection explicit.

class B : public IB, public A
{
public:
+ int AnInt()
+ {
+ return A::AnInt();
+ }

int AnInt2()
{
return 4;
}
};

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.

Inaccessible direct base' caused by multiple inheritance

This has nothing to do with overriding functions. It has to do with conversions. It really doesn't have to do with accessibility (i.e "private" or such) directly either. Here is a simpler example

struct A { int a; };
struct B : A { };
struct C : B, A { }; // direct A can't be referred to!

You can refer to the indirect A object by first converting to B and then to A:

B *b = &somec;
A *a = b;

You cannot do such with the direct A object. If you try to directly convert to A, it will have two possibilities. It follows that it is impossible to refer to the non-static data members of the direct A object given a Derived object.

Notice that accessibility is orthogonal to visibility. Something can be accessible even tho it's not visible (for example by refering to it by a qualified name), and something can be visible even though it's not accessible. Even if all the above derivations would be declared private, the problem would still show up: Access is checked last - it won't influence name lookup or conversion rules.

Also, anyone can cast to an unambiguous private base class with defined behavior (the C++ Standard makes an exception for this) using a C-style cast, even if normally access wouldn't be granted to do so. And then there are still friends and the class itself that could freely convert.



Related Topics



Leave a reply



Submit