我正在使用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;
在第一种情况下使用虚函数:
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
不是一个多态对象了.