请考虑以下设置。
class I
{
public:
virtual void F() = 0;
};
class A : public I
{
public:
void F() { /* some implementation */ }
};
class B : public I
{
public:
void F() { /* some implementation */ }
};
这使我可以编写类似以下的函数。
std::shared_ptr<I> make_I(bool x)
{
if (x) return std::make_shared<A>();
else return std::make_shared<B>();
}
在这种情况下,我要为继承和多态性付出一些代价,即拥有一个vtable,并且在按如下方式使用时不能内联对
F
的调用(如果我错了,请纠正我)。auto i = make_I(false);
i->F(); //can't be inlined
我想知道的是,当使用
A
或B
作为在堆栈上分配的对象时,是否必须支付这些相同的费用,如以下代码所示。A a;
a.F();
在堆栈上分配时,
A
和B
是否具有vtables?可以内联F
的电话吗?在我看来,编译器可以为继承层次结构中的类创建两种内存布局-一种用于堆栈,一种用于堆。这是C++编译器会/可能做的吗?还是有理论或实践上的原因?
编辑:
我看到一条评论(看起来好像已删除)实际上提出了一个要点。您可以始终执行以下操作,然后在堆栈上分配
A a
可能不是我想要达到的重点...A a;
A* p = &a;
p->F(); //likely won't be inlined (correct me if I'm wrong)
也许用一种更好的方式来表述它是“对于在堆栈上分配并用作“常规值类型”的对象,其行为是否有所不同?”如果您知道我的意思,但是有更好的表达方式,请在这里用术语帮助我!
我要说明的问题是,可以在编译时将基类的定义“扁平化”为要在堆栈上分配实例的派生类。
最佳答案
我认为您的问题确实与编译器是否具有对象的静态知识并且可以取消对vtable的查找有关(您在编辑中提到了此问题),而不是与对象存在的位置(堆栈还是堆)有所区别。是的,在这种情况下,许多编译器可以取消虚拟调度。
关于c++ - 继承成本是相对于对象是在堆栈上分配还是在堆上分配?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16618688/