考虑以下设置。
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
在堆栈上分配时是否有虚表?可以内联对 F
的调用吗?
在我看来,似乎编译器可以为继承层次结构中的类创建两种内存布局 - 一种用于堆栈,一种用于堆。这是 C++ 编译器将/可能做的事情吗?或者有什么理论上或实践上的原因它不能吗?
编辑:
我看到一条评论(看起来像是被删除了)实际上提出了一个很好的观点。您始终可以执行以下操作,然后在堆栈上分配的 A a
可能不是我想要达到的重点......
A a;
A* p = &a;
p->F(); //likely won't be inlined (correct me if I'm wrong)
也许更好的表达方式是“在堆栈上分配的对象的行为是否不同并用作'常规值类型'?”如果您知道我的意思但有更好的表达方式,请帮我解决术语问题!
我想表达的意思是,您可以在编译时切实可行地将基类的定义“扁平化”到您正在分配堆栈实例的派生类中。
最佳答案
我认为你的问题确实与编译器是否具有对象的静态知识以及是否可以省略 vtable 查找有关(你在编辑中提到了这一点),而不是对象所在的位置是否有区别 - 堆栈或堆。是的,在这种情况下,许多编译器可以省略虚拟分派(dispatch)。
关于c++ - 继承成本是否与对象是分配在栈上还是堆上有关?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16618688/