I am trying to understand a compile error from the latest version of VC++. The error occurs in a class that inherits from two base classes and includes a virtual function that overrides functions in the base classes but has a different return type.
The code compiles and executes correctly in g++ and clang.
I would like to know if this VC++ error is a bug and, if so, is there a simple workaround that preserves the intent of the code?
The example code and error message are below:
#include <iostream>
using std::cout;
class Vr {};
class Ar : public Vr {};
class Br : public Vr {};
class Dr : public Ar, public Br {};
struct Vx {
virtual Vr* vf() {
cout << "Vx::vf() called.\n";
return 0;
}
};
struct Ax : virtual Vx {
virtual Ar* vf() override {
cout << "Ax::vf() called.\n";
return 0;
}
};
struct Bx : virtual Vx {
virtual Br* vf() override {
cout << "Bx::vf() called.\n";
return 0;
}
};
struct Dx : Ax, Bx {
// Uncomment the following line to resolve.
virtual Dr* vf() override {
cout << "Dx::vf() called.\n";
return 0;
}
};
int main()
{
Dx* dx = new Dx;
auto r = dx->vf();
cout << "r=" << r << '\n';
}
2>multInheritanceCovariantRetTest.cpp 1>Done building project
"multipleInheritanceTests.vcxproj" -- FAILED.
2>C:\wgreene\tests\c++\MiscTests\multInheritanceCovariantRetTest.cpp(31,15):
error C2555: 'Dx::vf': overriding virtual function return type differs
and is not covariant from 'Ax::vf' 2>
C:\wgreene\tests\c++\MiscTests\multInheritanceCovariantRetTest.cpp(16,15):
2> see declaration of 'Ax::vf' 2>
C:\wgreene\tests\c++\MiscTests\multInheritanceCovariantRetTest.cpp(31,15):
2> 'Vr': ambiguous base is not covariant
2>C:\wgreene\tests\c++\MiscTests\multInheritanceCovariantRetTest.cpp(31,15):
error C2555: 'Dx::vf': overriding virtual function return type differs
and is not covariant from 'Bx::vf' 2>
C:\wgreene\tests\c++\MiscTests\multInheritanceCovariantRetTest.cpp(23,15):
2> see declaration of 'Bx::vf' 2>
C:\wgreene\tests\c++\MiscTests\multInheritanceCovariantRetTest.cpp(31,15):
2> 'Vr': ambiguous base is not covariant
Is there a simple workaround that preserves the intent of the code?
Adding virtual inheritance for the return type, and adding explicitly the virtual base to Dx
makes msvc happy (and other compilers too):
class Vr {};
class Ar : public virtual Vr {};
// ^^^^^^^
class Br : public virtual Vr {};
// ^^^^^^^
class Dr : public Ar, public Br {}; // Dr now has only 1 Vr as base instead of 2
// ...
struct Dx : virtual Vx, Ax, Bx {
// ^^^^^^^^^^^
virtual Dr* vf() override {
cout << "Dx::vf() called.\n";
return 0;
}
};