在C++ 0X中评估auto类型

mka*_*aes 13 c++ c++11

我正在使用C++ 0X标准中的自动功能,但我很困惑如何做出类型的决定.请考虑以下代码.

struct Base
{
    virtual void f()
    {
        std::cout << "Base::f" << std::endl;
    }
};

struct Derived : public Base
{
    virtual void f()
    {
        std::cout << "Derived::f" << std::endl;
    }
};

int main()
{
    Base* dp = new Derived;
    auto b1 = *dp;
    auto& b2 = *dp;
    std::cout << typeid(b1).name() << std::endl;
    std::cout << typeid(b2).name() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

它将打印Base和Derived.
但是为什么被auto&评估为参考衍生而不是参考基础?
更糟糕的是将代码更改为:

struct Base{};
struct Derived : public Base{};

int main()
{
    Base* dp = new Derived;
    auto b1 = *dp;
    auto& b2 = *dp;
    std::cout << typeid(b1).name() << std::endl;
    std::cout << typeid(b2).name() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

返回两种类型的Base.那么为什么类型取决于虚函数?我使用的编译器是VS2010.任何人都可以给我一个提示,我可以在标准中找到这种行为的定义吗?

Dav*_*eas 11

auto在两种情况下都是屈服Base,而不是衍生.在第一种情况下,您正在切割对象(在父级别进行复制),而在第二种情况下,因为它是一个引用,您将获得Base&实际Derived对象.这意味着所有虚函数调用都将被调度到该Derived级别的最终覆盖.

typeid对于多态类型,运算符具有与非多态类型不同的行为.如果应用于对多态类型的引用,它将在运行时执行类型检查并生成实际对象的类型.如果它应用于对象或对非多态类型的引用,则它将在编译时解析为对象或引用的静态类型.

要验证auto推断的内容,可以使用稍微不同的测试:

void test( Base& ) { std::cout << "Base" << std::endl; }
void test( Derived& ) { std::cout << "Derived" << std::endl; }
Run Code Online (Sandbox Code Playgroud)

然后调用该函数并查看它正在解析的类型.我希望编译器选择第一个重载,因为auto& a = *dp;应该相当于Base& a = *dp;

  • @Mat:执行`typeid`检查的决定取决于类型,而不是应用于它的操作.如果类型具有虚函数,并且`typeid`的参数是引用,那么它将在运行时执行测试.否则它将在编译时解析类型.*虚函数的存在*很重要,而*调用*对这些函数没有影响.即使代码没有调用它们,也不是技术上(即根据标准)使用非纯虚函数*. (3认同)

Naw*_*waz 7

在第一种情况下使用虚函数:

auto b1 = *dp;
auto& b2 = *dp;
Run Code Online (Sandbox Code Playgroud)

第一行导致对象切片,这意味着b1是一个类型的对象Base,因此它打印Base.第二行是创建一个类型的对象,Base&它是对指向的实际对象的引用dp.实际的对象是类型Derived.因此它打印Derived.

第二行相当于以下内容:

Base & b = *dp; //this is also a reference to the actual object
std::cout << typeid(b).name() << std::endl;
Run Code Online (Sandbox Code Playgroud)

它会打印什么?Base?不会Derived.这将打印出来.自己看看:


现在,第二种情况:当你没有虚函数Base,然后dp指向与创建子对象的对象new

Base* dp = new Derived; //dp gets subobject
Run Code Online (Sandbox Code Playgroud)

这就是为什么你Base甚至auto &因为dp不是一个多态对象了.