C++ では、仮想関数をインライン化できると理解していますが、通常、インライン化のヒントは無視されます。インライン仮想関数はあまり意味がないようです。
そうですか?
インライン仮想関数が優れているケースを挙げられる人はいますか?
C++ では、仮想関数をインライン化できると理解していますが、通常、インライン化のヒントは無視されます。インライン仮想関数はあまり意味がないようです。
そうですか?
インライン仮想関数が優れているケースを挙げられる人はいますか?
この質問に完全に答えるためには、存在するという性質がvirtual
関数自体とその関数への呼び出しに独立して適用されることを理解する必要があります。仮想関数と非仮想関数があります。これらの関数には、仮想呼び出しと非仮想呼び出しがあります。
の性質についても同様ですinline
。インライン関数と非インライン関数があります。また、これらの関数にはインライン呼び出しと非インライン呼び出しがあります。
これらのプロパティvirtual
とinline
- 関数自体に適用された場合、競合しません。彼らには単に理由がなく、衝突する機会がありません。関数自体の指定子が変更する唯一のことinline
は、その関数の One Definition Rule を変更することです: 関数は複数の翻訳単位で定義できます (そして、それが使用されるすべての翻訳単位で定義する必要があります)。指定子の唯一のvirtual
変更点は、その関数を含むクラスがポリモーフィックになることです。関数自体には実際の影響はありません。
virtual
したがって、関数を宣言するとinline
同時に、まったく問題はありません。対立には何の根拠もありません。C++ 言語では完全に合法です。
struct S {
virtual void foo();
};
inline void S::foo() // virtual inline function - OK, whatever
{
}
ただし、人々がこの質問をするとき、通常は関数自体のプロパティには関心がなく、むしろ関数に対して行われる呼び出しの特性に関心があります。
仮想呼び出しの決定的な特徴は、実行時に解決されることです。つまり、真の仮想呼び出しをインライン化することは通常不可能です。
S *s = new SomeType;
s->foo(); // virtual call, in general case cannot be inlined
ただし、呼び出し自体が非仮想である場合 (仮想関数に移動しても)、インライン化はまったく問題になりません。
S *s = new SomeType;
s->S::foo(); // non-virtual call to a virtual function, can easily be inlined
もちろん、場合によっては、最適化コンパイラがコンパイル時に仮想呼び出しのターゲットを特定し、そのような仮想呼び出しをインライン化できる場合もあります。場合によっては簡単です。
S ss;
ss.foo(); // formally a virtual call, but in practice it can easily be inlined
場合によっては、より複雑になりますが、それでも実行可能です。
S *s = new S;
s->foo(); // virtual call, but a clever compiler might be able
// to figure out that it can be inlined
通常の状況では、仮想関数は関数 (クラスの vtable に含まれる) へのポインターを介して呼び出されます。そのため、関数が呼び出される実際の型をコンパイラが静的に決定できる場合にのみ、仮想関数呼び出しをインラインで生成できます。単にクラス X または X から派生したものでなければならないということではありません。
インライン仮想関数が最初に意味を持つのは、パフォーマンスが重要な状況にあり、コンパイラが実際の型を静的に決定できるようにする方法でクラスが頻繁に使用されることがわかっている場合です (少なくとも 1 つのターゲット コンパイラがポインター経由で呼び出します)。
仮想関数をインラインとして持つことができます。関数呼び出しをインラインにするかどうかの決定は、コンパイル時に行われるだけではありません。コンパイルからrutimeまでのいつでも可能です。この記事はハーブサッターから参照できます。インラインRedux