MSVC:协变返回类型和虚拟继承

时间:2017-05-21 09:08:21

标签: c++ visual-c++ visual-studio-2013 virtual-inheritance covariant-return-types

我不确定这是否是visual-c ++编译器中的错误或未定义的行为。

设置

struct DummyBase { virtual ~DummyBase() = default; };
struct DummyDerived : virtual public DummyBase {};

只使用虚拟继承的类和派生类

DummyDerived derived;
DummyBase* base = &derived;

std::cout << "Derived : " << &derived << std::endl;
std::cout << "Base    : " << base << std::endl;

DummyDerived*强制转换为DummyBase*时,指针会偏移。这似乎是由虚拟继承引起的:

Derived : 00000000002CF838
Base    : 00000000002CF840

即使指针值不同,比较也会返回true:

std::cout << "IsSame  : " << (base == &derived) << std::endl << std::endl;

输出:

IsSame  : 1

到目前为止一切顺利。

问题

问题出现在以下设置中:

 struct IBaseReturner
 {
   virtual DummyBase* Get() = 0;
 };

 struct IDerivedReturner : public virtual IBaseReturner
 {
   virtual DummyDerived* Get() = 0;
 };

 struct BaseReturner : public virtual IBaseReturner
 {
 };

 struct DerivedReturner : public BaseReturner, public virtual IDerivedReturner
 {
   DummyDerived* Ptr;
   virtual DummyDerived* Get() override { return Ptr; }
 };

这里我们有类的接口和实现,其方法返回通过协变返回类型覆盖DummyBaseDummyDerived。再次使用虚拟继承。

// Setup
DerivedReturner returner;
returner.Ptr = &derived;
IBaseReturner* baseReturner = &returner;

现在从DummyDerived*DerivedReturner返回DummyBase*来自同一回归者IBaseReturner

DummyDerived* derivedOriginal = returner.Get();
DummyBase* baseFromInterface = baseReturner->Get();

比较obove:

std::cout << "Derived Original    : " << derivedOriginal << std::endl;
std::cout << "Base from Interface : " << baseFromInterface << std::endl;

输出

Derived Original    : 00000000002CF838
Base from Interface : 00000000002CF838

与上面不同,指针具有SAME值。 现在比较一下:

std::cout << "IsSame  : " << (baseFromInterface == derivedOriginal) << std::endl;

输出:

IsSame  : 0

比较返回false即使地址相同也很难。这是预期的,因为指向DummyBase的指针应具有不同的值。 在尝试dynamic_cast时也是如此:

std::cout << dynamic_cast<DummyDerived*>(baseFromInterface);

抛出了expception:

unknown file: error: C++ exception with description "Access violation - no RTTI data!" thrown in the test body.

显然,因为指针没有正确偏移。

结论

似乎在调用IBaseReturner::Get时,visual-c ++编译器无法执行必要的指针算法来将DummyDerived*强制转换为DummyBase*。这发生在vs2013和vs2015(没有尝试任何其他版本)。此外,当使用gcc编译时,它可以正常工作。

问题

虽然设置可能有点复杂但问题却相当简单:

这是一个msvc错误还是我导致了未定义的行为?

添加了一个在线示例:http://rextester.com/KHZXGQ27304

0 个答案:

没有答案