1

非仮想派生を使用する場合、コンパイラによって何が生成されるのか疑問に思っています。

template< unsigned int D >
class Point
{
     int[D];
    // No virtual function
    // ...
};
class Point2 : public Point<2> {};
class Point3 : public Point<3> {};

ここでの派生は、コンパイル時のチェックのみを意味しますか? それとも他のオーバーヘッドがありますか?

Point2or を直接使用すると、コンパイラが同じサイズのオブジェクトを生成することに気付きましたPoint<2>。派生によって vtable が発生しなかったと推測されるため、仮想呼び出しは行われません。

何か不足していますか?


環境

特定のクラス テンプレートの定義済みの特殊化をいくつか提供したいと考えています。私はtypedefから始めました:

template< unsigned int D >
class Point
{
     int[D];
};
typedef Point<2> Point2;
typedef Point<3> Point3;

残念ながら、これにより、クライアントは「単純な」前方宣言を使用できなくなります。

// No #include <Point.h>
class Point2;    // 'Point2': redefinition; different basic types
class Point3;    // 'Point3': redefinition; different basic types

次に、このかなり直感的でないコードを記述することが必須になります。

// No #include <Point.h>
template< unsigned int > class Point;
typedef Point<2> Point2;
typedef Point<3> Point3;

これが、typedef を破棄し、非仮想派生を使用した理由です。それでも、私はすべての意味が何であるか疑問に思っています。

(別の戦略は、前方宣言を専用のヘッダー ファイルに 1 回記述することです#include <iosfwd>。)

4

4 に答える 4

1

わかりました、これまで誰もあなたの質問に対する実際の答えをあなたに与えていないようです:

いいえ、非仮想派生へのオーバーヘッドはありません。コンパイラはvtableを作成する必要はなく、仮想関数呼び出しもありません。すべて問題ありません。これは通常、基本クラスのインスタンスを派生クラスの先頭に配置するだけで実装されるため、派生クラスへのポインターを基本クラスへのポインターとしても扱うことができます。そして、すべてがうまくいきます

もちろん、コンストラクター呼び出しは転送する必要がありますが、通常はインライン化され、そのオーバーヘッドも排除されます。

ただし、複数の基本クラスを使用する場合は、わずかなオーバーヘッドが発生する可能性があります(コンパイラーの実装方法によって異なります)。おそらくそれほど多くはありませんが(thisポインタは時々調整する必要があります)、理論的にはそこにあります。

于 2010-09-28T09:34:42.847 に答える
0

次の理由により、私は常に前方宣言 (typedef 宣言) を使用します。

  1. 継承は、ジェネリックの代替手段です。
于 2010-09-21T18:33:08.543 に答える
0

継承の問題は、コンストラクターを再定義する必要があることです。

標準的な解決策 (なぜ望まないのかわかりません) は、専用のヘッダーです。

// File PointFwd.h
#ifndef POINT_FWD_H
#define POINT_FWD_H 1

template <unsigned> class Point;

typedef Point<2> Point2;
typedef Point<3> Point3;

#endif

クライアントは、"PointFwd.h"必要なものを前方宣言するためにインクルードするだけで済みます。

于 2010-09-28T08:58:41.873 に答える
0

ここで typedef を使用する際の問題が何であるかはよくわかりません。これは、typedef が意図したものです。名前空間での作業にはいくつかの制限があると思いますが、ここではそうしているようには見えません。次のようなものがよく見られます。

General.h

#include <map>
#include <string>

class MyObj1;
class MyObj2;

typedef map< string, MyObj1 > MyObj1Map;
typedef map< string, MyObj2 > MyObj2Map;

その後、それをソースコードに含めることができますが、コンパイラがサイズを知る必要がある場所 (つまり、宣言内の参照とポインター以外)の定義MyObj1と場所を含めることを忘れないでください。MyObj2

于 2010-09-21T16:18:35.177 に答える