次の例を考えます。
class A
{
protected:
static void useful_function_without_side_effects() {...}
}
class B : private A
{
// B has no friends :(
public:
void travel_back_in_time() { super_useful_function(); }
}
質問1:コンパイラが基本クラスAを最適化することは許可されますか?この基本クラスは実際にはBに影響を与えないため、または実行時の動作にはまったく影響しませんか?
質問2:継承がこのようにプライベート仮想として宣言された場合、これは変更されますか?
class B : private virtual A
非多態性クラスには、実行時に完全に代表がありません。存在する可能性があるのは、関数と見なされるオブジェクトとメソッドだけです。このクラスは、オブジェクトの一部にアクセスし、メソッド呼び出しを定義どおりに解決するようにコンパイラーに指示するだけです。直接解決されると、すべてがランタイムコードにハードコードされます。private
修飾子は、ここには何も変わりません。
Bによって派生したAクラス(フィールドを持たない)は、クラスBのオブジェクトに「サイズを追加」しません。これは、Aクラスにフィールドがない場合は常に当てはまりますが、sizeof(A)は少なくとも常に1になります。Bのサイズがすべてのフィールドと基本クラスのサイズの合計でなければならないという規則もありませんが。
これにより、Bクラスにサイズが追加されます。規格はどのように正確ではありません。通常の実装では、常にBクラスのサイズを1ポインターのサイズに加えて、クラスAの可能なサイズだけ拡張します。
通常、仮想継承は「それ自体へのポインタ」を使用して実装されます。つまり、派生クラス(A)のサブオブジェクトは、物理的にオブジェクト全体の一部ですが、直接アクセスされることはなく、オブジェクト全体のポインターを介してアクセスされます。
これは、合計サイズが4のフィールドを持つフィールドレスAおよびBがある場合はさらに少なくなります。
物理的な継承:
B: [A: 0] [B extension: 4]
仮想継承:
B: [A virtual: <pointer size>] [B extension: 4] [A shared subobject: 1]
これらの順序は実装間で異なる場合がありますが、これはABI定義の一部であり、コンパイラのプライベートルールではありません(つまり、1つのプラットフォーム上のすべてのコンパイラが同じルールを使用する必要があります)。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加