8

次の設定を検討してください。

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();

スタックに割り当てられたときにvtablesを持っていますかA? B呼び出しをFインライン化できますか?

コンパイラは、継承階層内のクラスに対して、スタック用とヒープ用の 2 つのメモリ レイアウトを適切に作成できるように思えます。これは C++ コンパイラが行う/行う可能性があることですか? それとも、それができない理論的または実際的な理由がありますか?


編集:

実際に良い点を挙げたコメント (削除されたように見えます) を見ました。いつでも次のことを行うことができますがA a、スタックに割り当てられたものは、私が取得しようとしている重要なポイントではない可能性があります...

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

「スタックに割り当てられ、「通常の値型」として使用されるオブジェクトの動作は異なりますか?」というより良い言い方があります。私が何を意味するか知っているが、より良い言い方がある場合は、ここで用語を教えてください。

私が理解しようとしているポイントは、コンパイル時に、基本クラスの定義を、スタックにインスタンスを割り当てている派生クラスに「フラット化」できるということです。

4

2 に答える 2