【发布时间】:2016-12-06 20:14:37
【问题描述】:
我在使用 Microsoft Visual C++ 2015 时遇到了一些困难,并且能够通过一个小程序来重现该问题。给定以下类:
class BaseClass {
public:
BaseClass()
: mValue( 0 )
, mDirty( true )
{}
virtual ~BaseClass() {}
virtual int getValue() const { if( mDirty ) updateValue(); return mValue; }
protected:
virtual void updateValue() const = 0;
mutable bool mDirty;
mutable int mValue;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() {}
protected:
void updateValue() const override
{
mValue++;
mDirty = false;
}
};
class Impersonator {
public:
Impersonator() {}
// conversion operator
operator DerivedClass() const
{
return DerivedClass();
}
// conversion method
DerivedClass toDerived() const
{
return DerivedClass();
}
};
执行以下操作时出现“纯虚函数调用”错误:
void use( const BaseClass &inst )
{
// calls `getValue` which in turns calls the virtual function 'updateValue'
int value = inst.getValue();
}
int main()
{
// creates a temporary, then passes it by reference:
use( DerivedClass() ); // this works
// calls conversion operator to create object on stack, then passes it by reference:
DerivedClass i = Impersonator();
use( i ); // this works
// calls conversion method to create a temporary, then passes it by reference:
use( Impersonator().toDerived() ); // this works
// calls conversion operator to create a temporary, then passes it by reference:
Impersonator j = Impersonator();
use( j ); // causes a pure virtual function call error!
return 0;
}
鉴于我无法更改 void use(const BaseClass&) 函数,我可以更改 Impersonator 类中的任何内容以允许使用最后一次调用而不产生调试错误吗?
【问题讨论】:
-
如果你在最后一次调用
getValue中设置断点并检查 vtable 指针,MSVC 认为你有一个BaseClass对象,看起来不正确。 -
Cannot reproduce。 MVC 被认为不好。
-
检查生成的程序集表明,出于某种原因或其他 MSVC 决定调用
BaseClass::BaseClass以复制从operator DerivedClass返回的临时值,尽管BaseClass是抽象的。将复制构造函数显式声明为非公共使 MSVC 抱怨:error C2248: 'BaseClass::BaseClass' : cannot access protected member declaration in class 'BaseClass'. -
@AndreyChernyakhovskiy 我不知道。我构建了一个小的test case。旧的 gcc 和 msvc 打印“gotcha”,新的 gcc 和 clang 没有。为什么旧的 gcc 和 msvc 要从 Derived 中复制构造 Base?
-
@AndreyChernyakhovskiy MSVC 绝对是错误的,因为 BaseClass 是抽象的,并且永远不应创建此类的对象。如果复制构造在某种程度上是正确的操作(这对我来说似乎完全不可思议)MSVC 应该抱怨 BaseClass 是抽象的,而不是默默地继续复制构造它。
标签: c++ c++11 base-class pure-virtual visual-studio-2015