是否在堆栈或堆上分配对象的继承成本是什么?

Tim*_*lds 8 c++ inheritance

请考虑以下设置.

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 */ }
};
Run Code Online (Sandbox Code Playgroud)

这允许我编写如下函数.

std::shared_ptr<I> make_I(bool x)
{
    if (x) return std::make_shared<A>();
    else return std::make_shared<B>();
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我为继承和多态性支付一些费用,即有一个vtable,并且F当使用时调用不能内联如下(如果我错了,请纠正我).

auto i = make_I(false);
i->F(); //can't be inlined
Run Code Online (Sandbox Code Playgroud)

我想知道的是,当使用AB作为堆栈上分配的对象时,我必须支付相同的费用,如下面的代码所示.

A a;
a.F();
Run Code Online (Sandbox Code Playgroud)

AB在栈上分配有虚函数表?电话会F被内联吗?

似乎对我来说,编译器可以可行建立在继承层次的类两个内存布局-一个栈和一个用于堆.这是C++编译器将要/可能做的事情吗?或者是否存在理论或实践原因?


编辑:

我看到一条评论(看起来像是被删除了)实际上提出了一个好点.你总是可以做以下事情,然后A a在堆栈上分配可能不是我想要的重点......

A a;
A* p = &a;
p->F(); //likely won't be inlined (correct me if I'm wrong)
Run Code Online (Sandbox Code Playgroud)

也许用它来表达它的更好方法是"对于在堆栈上分配的对象的行为是否不同而被用作'常规值类型'?" 如果你知道我的意思,请用这个术语帮助我,但是有更好的方法!

我试图了解的一点是,在编译时,您可以将基类的定义"压扁"到您在堆栈上分配实例的派生类.

Sco*_*nes 7

我认为你的问题实际上与编译器是否具有对象的静态知识有关,并且可以忽略vtable查找(你在编辑中提到过这一点),而不是对象存在的位置 - 堆栈或堆.是的,在这种情况下,许多编译器可以忽略虚拟调度.