深度探索C++オブジェクトモデルの位置オブジェクトモデルの先端

6455 ワード

1,Template(テンプレート):
templateは、メモリ構成ポリシーなどの属性ブレンドまたはスレッド同期化制御に使用される反発メカニズムのパラメータ化技術に用いられる.これはtemplate metaprograms(テンプレートメタプログラミング)技術にも使用されています.class expression templates(クラス式テンプレート)は、実行期間ではなくコンパイル期間で評価されるため、重大な効率向上をもたらします.
 
2,templateの3つの主要な討論方向:
(1)、templateの声明、つまりtemplate class、template class member functionなどを宣言すると、何が起こるか.
(2)、「class object、inline nonmember、およびmember template functionsをどのように」インスタンス化するか.これらは、「コンパイル単位ごとにインスタンスが1つある」ものである.(3)、「nonmember、member template functions、static template class membersをどのように」インスタンス化するか.これらは、実行可能ファイルごとにインスタンスが1つしか必要としないものである.
PS:インスタンス化はプロセスが真のタイプと式をtemplate関連形式パラメータにバインドすることを示す.
 
3、次のtemplate classがあります.
template<class Type>
class Point
{
public:
    enum Status { unallocated, normalized };
    Point( Type x = 0.0, Type y = 0.0, Type z = 0.0 );
    ~Point();
   
    void* operator new(size_t);
    void operator delete(void*,size_t);
private:
    static Point<Type> *freeList;
    static int chunkSize;
    Type _x,_y,_z;
};

コンパイラがtemplate classを見たとき、何の反応もありません.つまりstatic data memberは使用できません.ネストenumも同じです.
ここで、enum Statusの真のタイプは、すべてのPointインスタンスで同じです.しかし、template Point classのインスタンスでのみアクセスおよび操作できます.次のように書くことができます.
Point<float>::Status s;//  

しかし、このように書くことはできません.
Point::Status s;//  

同様にfreeLsitとchunkSizeはプログラムにも使用できません.
Point::freeList;//  
Point::chunkSize;//  
Point<float>::freeList;//  
Point<float>::chunkSize;//  

次の文があります.
const Point<float> &ref = 0;

このとき、コンパイラはPointのfloatインスタンスをインスタンス化します.
次のように拡張されます.
//    
Point<float> temp(float(0));
const Point<float> &ref = temp;

参照は無物の代名詞ではないため、0は整数と見なされ、次のタイプのオブジェクトに変換されなければなりません.
Point<float>

class objectの定義は、コンパイラによって暗躍されても(tempのように)、プログラマーによって明示的に行われても:
const Point<float> origin;

いずれもtemplate classのインスタンス化をもたらします.
しかしながら、メンバー関数(少なくとも使用されていないもの)はインスタンス化されるべきではなく、使用される場合にのみ、C++標準がインスタンス化されることが要求される.
使用者が主導する「インスタンス化」ルールには、主に2つの理由があります.
(1),空間と時間効率の考慮.クラスには多くのメンバーfunctionsがある可能性がありますが、classインスタンスがすべてのメンバーfunctionを使用するとは限りません.
(2),未実現の機能.
たとえば、originの定義では、Pointのデフォルトのコンストラクタとコンストラクタを呼び出す必要があるため、この2つの関数のみをインスタンス化する必要があります.
4、これらの関数はいつインスタンス化されますか.
現在、2つのポリシーがあります.
(1)、コンパイル時;(2)、リンクするとき.
5,templateのエラーレポート
template classでは、タイプに関連するすべての検査がtemplateパラメータに関連する場合、実際のインスタンス化操作が発生するまで遅延しなければなりません.
6,Templateにおける名称決議法
scope of the template definition(templateを定義するドメイン)
scope of the template instantiation(templateをインスタンス化するドメイン)
//scope of the template definition

extern double foo( double );

template<class type>
class ScopeRules
{
public:
    void invariant()
     {
            _member = foo(_val);
     }
     type type_dependent()
     {
            return foo(_member);//          ,  type           
              //                foo()  。        
     }
private:
     int _val;
     type _member;
};

 
//scope of template instantiation
extern int foo( int );
ScopeRules<int> sr0;

次の呼び出しが表示されます.
sr0.invariant();

ではinvariant()で呼び出されるのはいったいどのfoo()関数のインスタンスなのでしょうか.
答え:呼び出されたのは
extern double foo( double );

理由:
Templateでは、nonmember name(メンバー名以外)の決定結果は、このnameの使用が「templateをインスタンス化するためのパラメータタイプ」に関連するか否かによって決定される.
関連しない場合はscope of the template definitionを使用してnameを決定します.
関連する場合はscope of template instantiationを使用してnameを決定します.
次のように呼び出されます.
sr0.type_dependent();

では、scope of template instantiationで宣言されたfoo()関数が呼び出されます.この例では、foo()関数が2つあり、この例の_memberタイプがintなので呼び出す
extern int foo( int );

もしそうなら
ScopeRules< double > sr0;

では呼び出します
extern double foo( double );

いずれにしても、「scope of template instantiation」によって決まる.
以下にまとめる.
scope of template definition//        template class
scope of template instantiation//          

7,メンバーfunctionのインスタンス化挙動
template functionsのインスタンス化:
現在、コンパイル期間ポリシーとリンク期間ポリシーの2つのポリシーがあります.
しかし、この2つのポリシーには共通の欠点があります.templateインスタンスが生成されると、コンパイル時間が大幅に増加することがあります.
8、異常処理
例外が発生した場合、コンパイルシステムは次のことを完了する必要があります.
(1)throw操作が発生した関数を検証する
(2)throw操作がtry区間で発生しているか否かを考える.
(3)もし,コンパイルシステムは異常タイプを各catch句と比較しなければならない.
(4),比較的一致する場合,プロセス制御はcatch句に渡すべきである.
(5)throwの発生がtryセグメントにない場合、またはcatch句が一致していない場合、システムは(a)構築されたすべてのローカルオブジェクトを破壊し、(b)スタックから木の現在の関数「unwind」(解除)を除去しなければならない.(c)プログラムスタックの次の関数に進み、上記の手順2~5を繰り返す.
---例外が放出されると、例外オブジェクトが生成され、通常は同じ形式の例外データスタックに配置されます.throwからcatch句に渡されるのは、例外オブジェクトのアドレス、タイプ記述器(または、例外タイプに関連するタイプ記述器オブジェクトを返す関数ポインタ)、および可能な例外オブジェクト記述器です.
9、(Type-safe Downcast)安全なダウンコンバート操作を保証する:
安全を保証するダウンコンバート操作は、実行中にポインタをクエリーして、表示されるオブジェクトの本当のタイプを指しているかどうかを確認する必要があります.したがって、type-safe downcastをサポートするには、オブジェクトスペースと実行時間に追加の負担がかかります.
(1)タイプ情報を格納するために追加のスペースが必要であり、通常はポインタであり、タイプ情報ノードを指す.
(2)実行期間のタイプ(run type)を決定するには、実行期間で決定する必要があるため、追加の時間が必要である.
 
C++のRTTI(ランタイムタイプ識別)メカニズムは、安全なdowncastデバイスを提供しますが、マルチステート(つまり、継承とダイナミックバインドを使用する)を示すタイプにのみ有効です.
どのようにしてこれらのタイプを見分けますか?
答え:class宣言は、1つのアクティブな複数の仮想関数を宣言することによって区別されます.
C++では、多態性を持つclassは、継承(または直接宣言)を含む仮想関数です.
10、参照はポインタではありません:
プログラム実行中にclassポインタタイプにdynamic_を適用cast演算子、trueまたはfalseが得られます.
(1)本物のアドレスを返すと,このオブジェクトの動的タイプが確認され,タイプに関するいくつかの操作が実行できるようになったことを示す.
(2)0に戻ると,何も指向していないことを意味し,この動的タイプの不確定なオブジェクトに別の論理で実行すべきであることを意味する.
 
 dynamic_cast演算子は参照にも適用されますが、non-type-safe castの場合、その結果はポインタで実行される場合と同じではありません.引用はポインタのように「自分を0にして「no object」を表すことはできないからです.
Waring:参照を0に設定すると、一時オブジェクトが生成され、そのオブジェクトの初期値が0になります.
したがってdynamic_castが参照で実行されると、次のことが起こります.
(1)実際に適切な継承クラスを参照するとdowncastが実行され,プログラムが続行できる.
(2)参照が本当に継承クラスでない場合,0を返すことができないためbad_を投げ出す.cast異常.