【復習】C++対象ベース3

49877 ワード

文書ディレクトリ
  • オブジェクトベース3
  • 向け
  • 1.変換関数
  • non-explicit-one-argument constructor
  • pointer-like class、スマートポインタ
  • Function-like class,擬似関数
  • member template,メンバーテンプレート
  • テンプレート特化及び偏特化
  • テンプレートテンプレートパラメータ、template template parameter
  • variadic templates(c++11)可変個数のテンプレートパラメータ
  • auto(c++11)自動変数タイプ
  • ranged-base for(c++11)簡略化forサイクル
  • reference
  • オブジェクトモデル:ダミーポインタvptrとダミーテーブルvtbl
  • Dynamic Binding,動的バインドと静的バインド
  • new、delete、malloc、free

  • オブジェクトベース3
    1.変換関数
    に表示されます.
    class Fraction{
    public:
        Fraction(int num,int den=1):m_numberator(num), m_denominator(den){}
        
        operator double() const{
            return (double)(m_numerator/m_denominator);
        }
    
    private:
        int m_numerator;   //   
        int m_denominator; //   
    }
    
    {
        Fraction f(3,5);
        double d = 4 + f;
        //          ,                
        int operator+(int& a1, const Fraction& a2);
        //                   4+f。    
        //     ,   Fraction          f  double  ,  double d=4+f;      。
    }
    

    上記はclassを他のタイプに変換することです.
    non-explicit-one-argument constructor
    パラメータが1つしか入力されていない(パラメータが1つしか入力されていない場合、すなわち他のパラメータはデフォルトパラメータであってもよい)コンストラクション関数は、explicit修飾ではなくデフォルト(implicit)である.すなわち、このコンストラクション関数は暗黙的な変換が必要な場合に呼び出される.
    class Fraction{
    public:
        Fraction(int num,int den=1):m_numberator(num), m_denominator(den){}
        
        Fraction operator+(const Fraction& f){
            return Fraction(....)
        }
    
    private:
        int m_numerator;   //   
        int m_denominator; //   
    }
    
    {
        Fraction f(3,5);
        Fraction d2 = f + 4;
        //                             ,    。
        //             4    ,  Fraction(int num, int den=1)      ,    4      Fraction  ,          。
        //         ,          operator+(const Fraction & f)
    	
        // !!!!
        //         explicit  ,  ,       ,      ,    d2=f+4    !
    }
    

    このメカニズムは実際には変換関数の逆操作であり,暗黙のタイプ変換である. 1 , , , ambiguous !
    pointer-like class、スマートポインタ
    ここではshared_について説明しますptrは、1つのclassを1つのポインタのようなものにして、ポインタができる操作で、このclassはすべてできます.しかし、classであり、強化ポインタに相当する機能をユーザーがカスタマイズできます.
    template<class T>
    class shared_ptr{
    public:
        //               ,            
        T & operator*() const{
            return *px;
        }
        
        T* operator->() const{
            return px;
        }
        
        //                 
        shared_ptr(T* p):px(p){}
        
    private:
        T* px;
        long* pn;
        .....
    };
    
    struct Foo{
        ....
        void method(){...}
    }
    
    {
        //   
        shared_ptr<Foo> sp(new Foo);
        //   sp      shared_ptr  ,              (     )        。
        Foo f(*sp);
        sp->method();
        //                 。
    }
    

    STLでの応用:反復器!
    Function-like class,シミュレーション関数
    クラスを関数のように設計すると、呼び出されます.カッコ呼び出しオペレータを再ロードします.標準ライブラリのシミュレーション関数は、特定のbase classを継承します.
    メンバーテンプレート
    クラスのメンバー関数はテンプレート関数です.
    #pragma once
    #include
    
    namespace member_template {
    
    //  
    class Fish{ };
    //   
    class Crap : public Fish{};
    
    //   
    class Bird {};
    //   
    class Sparrow : public Bird {};
    
    //        ,       ,     
    template<class T1, class T2>
    class Pair {
    public:
    	//        ,   first second       。           ,
    	//              ,       T1 T2  ,  T1 T2         。
    	Pair():first(T1()),second(T2()) {}
    
    	//        ,      T1 T2        ,             
    	Pair(const T1& t1, const T2& t2):first(t1),second(t2) {}
    
    	//       ,         .
    	template<class U1, class U2>
    	//   :                     。   p first   U1     this.first, T1   ,       。
    	Pair(const Pair<U1, U2>& p) : first(p.first), second(p.second) {}
    	
    	//     ,        
    	T1 first;
    	T2 second;
    };
    
    void test() {
    	Pair<Crap, Sparrow> p;
    	//    -    ,      -     ,     
    	Pair<Fish, Bird> p2(p); //    Pair p(Pair())
    	Pair<Crap, Sparrow> p3(p2); // error!   “const member_template::Bird”   “const member_template::Sparrow”(   31 ,       !)
    }
    
    }
    

    ここで、ユーザは、U 1およびU 2がT 1およびT 2のサブクラスであり、構文制約がないことを保証する必要がある.Javaの汎用タイプの上下限に比べて直感的です.
    STLでの応用:shared_ptr
    template<typename _Tp>
    class shared_ptr:public __shared_ptr<_Tp>
    {
    	...
    	template<typename _Tp1>
    	explicit shared_ptr(_Tp1* __p):__shared_ptr<_Tp>(__p){}
    	...
    }
    
    {
    	//   
    	Base1* ptr = new Derived1;// up-cast
    	shared_ptr<Base1> sptr(new Derived1);
    	//                 
    }
    

    テンプレートの特化と偏特化
    汎化:テンプレート.汎用を表す.
    特化:specialization.
    使用:特定のタイプに対して、特化処理を行います. .
    #pragma once
    #include
    #include
    
    using namespace std;
    
    namespace specialization {
    
    template<typename T>
    void print() {
    	cout << "         。。" << endl;
    }
    
    //    ,       ,     typename  class T
    template<>
    void print<int>() {
    	cout << "    int       。。" << endl;
    }
    
    template<>
    void print<string>() {
    	cout << "    string       。。" << endl;
    }
    
    void test() {
    	print<float>();
    	print<int>();
    	print<string>();
    
    	// result
    	//          。。
    	//     int       。。
    	//     string       。。
    }
    
    }
    

    汎化は全汎化と呼ぶことができ,対応する特化,また偏特化がある.partial specialization.
  • パラメータ個数の「バイアス」
  • パラメータタイプ範囲の「バイアス」
  • //         
    
    //   vector     ,          T,  ,    Alloc(  Alloc           )
    template<typename T, typename Alloc=...>
    class vector
    {
    	...
    }
    
    //          T   bool,      ,                , ,  vector       :A,B,C,D,E,      A,C,E,   BD      。
    template<typename Alloc=...>
    class vector<bool, Alloc>
    {
    	...
    }
    
    //         
    
    //     ,              
    template<typename T>
    class C{
        ....
    }
    
    //                   
    template<typename U>
    class C<U*>{
        ...
    }
    

    テンプレートテンプレートパラメータ、template template parameter
    template<typename T, template<typename T> class Container>>
    class XCls
    {
    private:
        Container<T> c;
    public:
        ...
    }
    /*
      XCls     ,        ,1,      T;2,          T class,    T    ,  class     ,        
    */
    
    {
        //   
        template<typename T>
        using Lst = list<T, allocator<T>>;
        
        //   !XCls      ,string  ,   string      list
        XCls<string,Lst> mylst;
        //   !  XCls list       XCls   
        XCls<string, list> mylst2;
    }
    

    ここで実現される効果は、コンテナのネストによく使用されます.
    variadic templates(c++11)可変個数のテンプレートパラメータ
    #pragma once
    #include
    #include
    
    using namespace std;
    
    namespace varicdic_tmp{
    
    	//   :         !   print          ,t2  ,   1    (t1),
    	//               print,    !
    	void print(){}
    
    	template<typename T, typename... Types>
    	void print(const T& t1, const Types&... t2 ) {
    		cout << typeid(t1).name() << "," << t1 << endl;
    		//         ,  t1       
    		//            ,  print             ,           t2             
    		print(t2...);
    	}
    
    	void test() {
    		print(7.5, "hello", 42, bitset<16>(999));
    	}
    
    	// result:
    	// double, 7.5
    	// char const[6], hello
    	// int, 42
    	// class std::bitset<16>, 0000001111100111
    }
    

    上記の例の3つの注意点:
  • 可変数テンプレートパラメータの定義方法typename... Types
  • 可変数テンプレートパラメータの使用方法args...、実パラメータ名+3点、ここで実パラメータ名は「1パッケージ」パラメータ
  • である.
  • 再帰的な押し出し条件を考慮する.printでは判定を空にしてもよいし、上記のようにprintを再ロードして再帰ジャンプ条件に対応してもよい.

  • auto(c++11)自動変数タイプ
    実際には,付与された右側の結果に基づいて左定義パラメータのタイプを自動的に推定するので,必要に応じて変数を同時に定義して推定することはできず,右側の推定ではなくauto変数を単独で作成することはできない.
    list<stirng> c;
    ...
    list<string>::iterator ite;
    ite = find(c.begin(), c.end(), target);
    //     c      string,     ,  ite        find            。            
    
    auto ite = find(c.begin(), c.end(), target);
    
    //   auto        ,       ,       .        !!!!
    auto ite; // error!!!
    ite = find(c.begin(), c.end(), target);
    

    Javaの汎用タイプの自動推定に似ていて、コンテナの操作でよく使われています.通常、コンテナを作成するときに、入力されたテンプレートパラメータが決定されることが多い.これにより、auto変数を使用できます.
    ranged-base for(c++11)簡略化forサイクル
    //  :decl   ,coll      
    for(decl : coll){
        statement
    }
    
    // c++2.0      {}       python tuple    。        ,      。
    for(int i : {2,3,4,5,6}){
        cout << i << endl;
    }
    
    //     auto         
    vector<double> vec;
    ...
    //       , elem     vec    
    for (auto elem : vec){
        cout << elem << endl;
    }
    //        ,   vec       3 
    for (auto& elem : vec){
        elem *= 3;
    }
    

    reference
    参照は元の変数の別名ですが、内部はポインタで実現されます.
  • 参照変数は初期値を設定する必要があります.
  • 参照変数は、参照されたオブジェクトを交換できません.

  • 論理的に参照される変数と参照される変数が同じ「もの」であることを満たすために、コンパイラは参照のためにいくつかの「仮想」を作成します.
    int x=0;
    int& r = x; //      
    int x2=5;
    
    // r        
    //        r   x2,  x r   5.
    r = x2;
    
    //   r     ,32      4  ,        r      x    ,r sizeof   x  , ,   x 1000     ,  r  1000  
    sizeof(r) == sizeof(x);
    //   ,              
    &x == &r;
    

    参照タイプを直接宣言する変数は少なく、通常、参照はパラメータ伝達の方法として使用されます.
    参照パラメータの利点:
  • 内部はポインタ伝達に相当し、速度が速い.ただし、パラメータの操作はすべてinplaceの操作であり、追加のコピーは発生せず、元の実パラメータで変更されることに注意してください.
  • は、呼び出し側と関数内部のコードが一致するように参照パラメータタイプを採用し、参照が参照対象の別名であり、論理的に一致する思想を体現している.
  • 同時に、参照タイプと元のタイプの2つのパラメータタイプの関数は同じ関数とみなされ、関数のリロード条件(署名の一部ではない)とすることはできない.(関数のconstタイプ、すなわちclassのconst関数のconstはリロード条件とすることができ、すなわち、方程式のconstは関数署名の一部である)
  • オブジェクトモデル:ダミーポインタvptrとダミーテーブルvtbl
    classに虚関数がある場合、classはデータの開始時にvptr、虚関数ポインタを追加し、すべての虚関数のアドレスを格納する虚関数テーブルvtblを指します.
    サブクラスは親のデータオブジェクトを継承しますが、vptrは継承されません.独自のvptrを持ちます.
    (詳細については以前から詳しく説明していました)
    Dynamic Binding、動的バインディングと静的バインディング
    動的バインド、すなわち関数の呼び出しは動的プロセスであり、多状態の特性として表現される.内部実装はvptrとvtblと虚関数である.
    #pragma once
    #include
    using namespace std;
    namespace dynamic_binding {
    
    class A {
    private:
    	int a, b;
    
    public:
    	A():a(1),b(2){}
    
    	virtual void vfunc1() {
    		cout << "A's vfunc1!" << endl;
    	}
    	void func2() {
    		cout << "A's func2!" << endl;
    	}
    
    };
    
    class B : public A {
    private:
    	int a, b;
    
    public:
    	B() :a(1), b(2) {}
    
    	virtual void vfunc1() {
    		cout << "B's vfunc1!" << endl;
    	}
    	void func2() {
    		cout << "B's func2!" << endl;
    	}
    };
    
    void test() {
    	B b;
    	A a = (A)b;
    	//       ,     A   ,       。
    	a.func2();  // A's func2!
    	a.vfunc1(); // A's vfunc1!
    	
    	A* c = new B;
    	c->func2();	 // A's func2!
    	//       (  )。  :1)  。2)           。3)   
    	c->vfunc1(); // B's vfunc1!
    }
    
    }
    
    

    new、delete、malloc、free
  • new、deleteはオペレータです.
  • newはmemoryを割り当ててからconstructor
  • を呼び出す.
  • deleteは先析構造であり、memoryを放出する.
  • newが成功すると、オブジェクトタイプのポインタが返されます.mallocはvoidタイプポインタを返し、強く回転する必要があります.
  • new失敗、bac_を投げ出すallocはnullを返さずに異常です.mallocに失敗してnullを返します.通常Cではmallocでnull判定を行い,C++ではnewではtry catch異常処理を採用すべきである.あるいは安全なnew、すなわち異常を抑制するnewを用いる.int* p = new(std::nothrow) int;//