C++ c++;为什么以下变量不';不能通过虚拟表

C++ c++;为什么以下变量不';不能通过虚拟表,c++,polymorphism,C++,Polymorphism,假设我们有这样一个代码: struct X{ virtual void foo(){} }; struct Y: X{ void foo() override{} } void test(Y& ref){ Y local_y; local_y.foo(); ref.foo(); } 我们这样做: struct X{ virtual void foo(){} }; struct Y: X{ void foo() override{} }

假设我们有这样一个代码:

struct X{
   virtual void foo(){}
};

struct Y: X{
   void foo() override{}
}
void test(Y& ref){
   Y local_y;
   local_y.foo();
   ref.foo();
}
我们这样做:

struct X{
   virtual void foo(){}
};

struct Y: X{
   void foo() override{}
}
void test(Y& ref){
   Y local_y;
   local_y.foo();
   ref.foo();
}
在第一个调用中(在某些编译器中),第一个调用根本不会经过
vptr
,而第二个调用会

这对我来说是有意义的,因为从我所知道的,引用和指针在C++中是多态的,而正则变量不是,所以不需要通过表。 然而,原因是这是一个编译器优化,因为

local_y
在堆栈上。因此编译器知道不要遍历虚拟表

虽然原因是相似的(可能是相同的),但我想知道——我的想法有意义吗?另外,
local_y
是否会有一个
vptr
?(我假设答案是肯定的,因为我们可能会做
Y&new\u Y=local\u Y
,而
new\u Y
需要有那个指针)

这对我来说是有意义的,因为从我所知道的,引用和指针在C++中是多态的,而正则变量不是,所以不需要通过表。 我的想法有意义吗

不,运行时多态性并没有以某种方式被“常规变量”禁用。虚拟函数是虚拟函数,在调用虚拟函数时应用运行时多态性。句号

人们喜欢说“运行时多态性只适用于引用和指针”,因为从语法上讲,如果不切掉对象的派生部分,很难找到反例

在你的例子中,你甚至不需要虚拟分派(你实际上只是在调用你想要调用的函数),所以整个问题都没有意义

然而,原因是这是一个编译器优化,因为局部y在堆栈上。因此编译器知道不要遍历虚拟表

这更有道理。可以证明名为
local_y
的对象是动态类型的
y
,因为它的声明就在函数中。因此,除了直接调用
Y
中定义的函数
foo()
,不需要任何神奇的滑稽动作

你可以称之为“优化”;我称之为“编译器在没有不必要的步骤的情况下完成它的工作”

当地人会有一个vptr吗


可能吧,但这只是因为编译器不会根据本地使用情况有选择地更改类定义的一部分,从而获得太多好处。

我建议您不要再关注实现细节。如果编译器不需要做任何事情,它就不会做任何事情。您的代码描述了一个程序。你不是在给电脑编程;这是你的编译器的工作。为什么
ref.foo()
要检查
vptr
?从您的示例来看,它不像
Y
是一个多态类。你是说<代码>无效测试(X&REF){<代码> >吗?在这两种情况下都应该调用正确的<代码> Foo< /Cuff>函数。编译器如何调用它是一个实现内部细节。它是否或“不通过VPTR”是无关紧要的,C++语言标准甚至不定义或要求一个“VPTR”。@scohe001在什么情况下
Y
不是多态类?如果
Y&ref
指的是
Z
,又该怎么办?啊,看来继承多态函数会让你自己多态()。我没有意识到。好的调用@Asteroids。它是否有vptr取决于优化设置。在-O2或更高级别,它甚至不会生成
y_local
更不用说它是vptr。看到了吗?当调用函数时,一个不是指针或引用的对象会通过它的动态表吗?@EL_9否,这就是为什么人们错误地认为多态性“只适用于”指针。事实是,它只适用于指针。如果动态类型是静态已知的,则不需要魔法。还要记住,vtables是一个实现细节。