动态强制转换引用和自动转换



我在使用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没有推导出正确的类型还是怎么的?

我还发现了一个肮脏的伎俩,仍然使用auto:

void ThirdClass::demoMethod(Base& obj) {
    auto buffer=dynamic_cast<Derived*>(&obj);
    anotherMethod(*buffer);
}

你从auto得到Derived。用这个代替:

auto & buffer = dynamic_cast<Derived&>(obj);

§7.1.6.4/7:

当使用占位符类型声明的变量初始化时[…]推导出的返回类型或变量类型由类型确定它的初始化式。设T为变量的声明类型或者函数的返回类型。如果占位符是auto类型说明符,则使用的规则确定推断的类型模板参数推导。[…]从T中获取Pauto出现在新创建的类型模板中参数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);

现在,PU&:

template <typename U>
void f(U&);
当然,

U仍然被推断为Derived,但P的类型(实际上是buffer的类型)是Derived&

最新更新