3

コードには、いくつかの特別なクラスといくつかの通常のクラスがあります。特別なクラスには別の扱いをする必要があるため、それらを区別したいと思います。これらの特別なクラスはすべてベースです (他のクラスの子ではありません)。

classそれを達成するために、空の を使用して継承を挿入することにより、ソース コード内の特別な es をトークン化していますstruct

struct _special {};  // empty class
class A : public _special {  // A becomes special
...
};
class B {  // 'B' remains normal
...
};
class D : public A {  // 'D' becomes special due to 'A'
...
};

必要に応じて、is_base_of<Base,Derived>. 別の方法はtypedef、特別なクラス内で使用することでした:

class A {
  public: typedef something _special;
};

問題は、Aの子が複数のクラスから継承している場合、あいまいな が存在することtypedefです。

質問: empty を使用した継承などのインターフェイスclass _specialを追加すると、現在のコードになんらかの形で影響を与えますか (たとえば、オブジェクトの構造化、コンパイル エラーなど) ?

4

3 に答える 3

3

すべてではないにしてもほとんどの適切なコンパイラは、単純なケースに対して空のベース最適化 (EBO) を実装しています。つまり、空のベースから継承することによってオブジェクトのサイズが大きくなることはありません。ただし、クラスが複数の方法で空のベースから継承する場合、同じタイプの異なる空のベースに対して異なるアドレスが必要になるため、最適化が不可能になる場合があります。それを防ぐために、通常、空のベースを、派生クラスを引数として取るテンプレートにしますが、is_base_of使用できなくなります。

個人的には、この分類を外部に実装します。テンプレートの特殊化では、special から派生したクラスが間接的にも special と見なされるという望ましい結果が得られません。C++11 を使用しているように見えるので、次のようにします。

std::false_type is_special( ... );
std::true_type is_special( A const* );

is_base_of<T, _special>と置き換えdecltype( is_special( static_cast<T*>(0) ) )ます。C++03 ではsizeof、分類関数が異なるサイズの型を返すようにすることで、トリックを使用して同じことが実現できます。

typedef char no_type;
struct yes_type { no_type _[2]; };

no_type is_special( ... );
yes_type is_special( A const* );

is_base_of<T, _special>と置き換えsizeof( is_special( static_cast<T*>(0) ) ) == sizeof( yes_type )ます。その分類チェックをヘルパー クラス テンプレート内にラップできます。

于 2011-10-09T08:32:52.253 に答える
3

メモリ内のオブジェクトのレイアウトは、C++ 標準で部分的にしか指定されていませんが、ほとんどのコンパイラが使用する特定の規則があります。空の型は少しのメモリを占有します (そのため、ポインタに ID を与えるメモリ アドレスが割り当てられます)。通常、この余分なメモリはわずか 4 バイトであり、ほとんどの目的で心配する必要はありません。一方、空の型から継承する場合は、オブジェクトの残りの部分がスペースを占有するため、オブジェクトのサイズを増やすべきではありません。とにかくアドレスを持つことになります。

単一継承オブジェクトを使用している場合、メモリの最初のビットが最初の基底クラスのように配置され、次にメモリがチェーン内の後のクラスのメンバーを保持するように配置されます。仮想関数がある場合は、おそらく最初に、仮想ポインター用の場所もあります。ある型を別の型から派生させる場合は、通常、仮想デストラクタ、コピー コンストラクタ、およびコピー代入演算子の「3 つのルール」に従う必要があります。したがって、仮想ポインターが得られます。これもおそらく 4 バイトであり、大したことではありません。

多重継承に入ると、オブジェクトは構造的に非常に複雑になり始めます。それらは、関数が探しているメンバーを見つけることができるように、それ自体のさまざまな部分へのさまざまなポインターを持ちます。

とはいえ、これをモデル化するために継承を使用するかどうかを検討してください。おそらく、オブジェクトに bool メンバー変数を与えることは良い考えです。

于 2011-10-09T08:33:05.600 に答える
0

損傷またはオブジェクトの構造化で何を意味するのかわかりませんが (詳しく説明しますか?)、コンパイラ エラーは発生しないはずです。_special にはデフォルトのコンストラクターがあり、パフォーマンスに関してコンパイラー空の基本クラスの最適化を適用します。

そうは言っても、typedef を使用してクラスにタグを付けるというオプションは、より優れた、より明確で拡張可能なソリューションになる可能性があります。そして、A の子がすべて _special から継承する可能性のある他の複数のクラスから継承するのと同じくらいあいまいです。

于 2011-10-09T08:26:29.670 に答える