使用auto和dynamic_cast时,我遇到了一个非常奇怪的行为。 这是我的课程:
class BaseInterface {
public:
virtual void someMethod()=0;
};
class Derived:public BaseInterface {
public:
virtual void someMethod1()=0;
void someMethod()override;
};
当然,有些类可以实现所有派生方法。
然后有第三个类看起来像这样:
class ThirdClass {
public:
void demoMethod(BaseInterface&);
void anotherMethod(Derived&);
};
void ThirdClass::demoMethod(BaseInterface& obj) {
auto buffer=dynamic_cast<Derived&>(obj);
anotherMethod(buffer);
}
当我使用gcc编译它时,我得到一个“无法分配抽象类型的对象”错误。而当我替换
auto buffer=...
与
Derived& buffer=...
一切都很好。为什么会这样?自动没有推断出正确的类型或什么?
此外,我发现仍然使用auto的肮脏技巧:
void ThirdClass::demoMethod(Base& obj) {
auto buffer=dynamic_cast<Derived*>(&obj);
anotherMethod(*buffer);
}
答案 0 :(得分:6)
您从Derived
获得auto
。请改用:
auto & buffer = dynamic_cast<Derived&>(obj);
答案 1 :(得分:4)
§7.1.6.4/ 7:
初始化使用占位符类型声明的变量时[...] 推导出的返回类型或变量类型由类型确定 它的初始化程序。 [...]让
T
成为变量的声明类型 或返回函数的类型。 如果占位符是auto
type-specifier,推导出的类型是使用规则确定的 模板参数推导。 [...]通过替换P
来获取T
使用新发明的类型模板发生auto
参数U
[...]。 使用模板规则为U
推算一个值 函数调用(14.8.2.1)中的参数推导,其中P
是a 函数模板参数类型和相应的参数是 初始化程序。强>
因此,为了熟悉该过程,请查看用于推断buffer
类型的实际规则:如果更改会发生什么
template <typename U>
void f( U );
到
void f( Derived& );
使用f
类型的左值调用Derived
时?显然,对于功能模板,U
将被推断为Derived
,然后产生扣减失败。
这与示例中扣除占位符类型直接对应 - auto
将替换为Derived
,但失败,因为Derived
是抽象的。
一般来说,如果你写
auto obj = …;
obj
永远不会成为参考,就像在调用上述函数模板时永远不会将U
推断为引用类型一样。
相反,请使用auto&
:
auto& buffer = dynamic_cast<Derived&>(obj);
现在,P
为U&
:
template <typename U>
void f(U&);
U
当然仍被推断为Derived
,但P
的类型 - 实际上是buffer
的类型 - 是Derived&