C++ノート01(基礎文法、ポインタ、テンプレート、対象向け初歩)


C++は大学の时に勉强しましたが、その时は多くのことを知っていて、ずっと耻ずかしくて、今日はC++のいくつかの使い方をまとめて、前の说明に対して、みんなを助けることができることを望んでいます.環境はC++98,CLion 2017です.C++の文法は基本的に後相互換なので、C++11、C++17でも問題ありません.
  • カンマ演算子
  • a=3*5,a*4;
    // a = 15 
    b=(a=3*5, a*4);
    //a = 15, b = 60
    b = (a = 3*5, a=a*4);
    //a = 60, b = 60
    b = a = 3*5, a=a*4;
    //a = 60 , b = 15
    

    左から右へ演算すると、式全体の値が右の値になります.優先度が高い世代から低い;&&短絡特性を持ち、左式が偽で、式全体が偽である.短絡特性も有する、左側は真全体が真3である.3つの演算子:
    a = 1 > 2?100:200;
    // a = 200 
    

    1 > 2?100:200は全体的にブール型で、式2と3のタイプは異なってもよく、条件式の最終タイプは条件式の中で高いタイプである(清華大学C++教材).sizeof演算は、1つのタイプのバイト数を計算することができる.
    sizeof(   /   )// int 4 float 4 double 8 char 1;
    
  • ビット演算
  • 3 & 5 //    
    c = a & 0xff; //     a    
    1||2; //   ,           1
    1^2;//    
    1<<1;
    2>>1;//   ,     
    
  • 隠し変換:低タイプから高タイプに変換されます.たとえば、1-true 0-true浮動小数点は整数に割り当てられます.小数点は切り捨てられ、
  • に四捨五入されません.
  • 明示的な変換:次のいくつかの書き方は完全に等価です:
  • int(z) <=> (int)z <=> static_cast<int>(z);
    
  • 取込残
  • /   
    %   
    
  • カスタムタイプカスタムタイプカスタムタイプを使用すると、読み取り可能性が向上します:
  • typedef double Area, Volume;
        typedef int Natrual;
        Natrual i1, i2;
        Area a;
        Volume v;
    using area = double; //typedef     
    
  • 列挙タイプ
  • enum WEEKDAY {SUNDAY, MONDAY, TUESDAY}; //     
        cout<<SUNDAY;
        cout<<MONDAY;
    
        //0 1
    
        enum WEEKDAY2 {SUNDAY_2=7, MONDAY_2, TUESDAY_2};
        cout<<SUNDAY_2;
        cout<<MONDAY_2;
    
        //7 8
    

    値は重畳され、整数は列挙タイプに直接コピーできません(列挙タイプに変換されない限り、下を参照).列挙タイプの場合、整形されたサブセットはintと比較できます.列挙タイプに変換:
    enum WEEKDAY2 {SUNDAY_2=7, MONDAY_2, TUESDAY_2};
        WEEKDAY2 day = SUNDAY_2;
        cout << day;
        // 7
    WEEKDAY2 a_day;
    int a=2;
    a_day = WEEKDAY2(a);
    //int             ,        ;
    
  • autoおよびdecltypeの使用
  • auto val = val1+val2; //val    val1+val2    
    
    int i;
    decltype(i) j=2.123;
    cout<<j;
    // 2
    

    jとiは同じタイプになるのでint
  • 形式のパラメータは定義時にメモリ領域を占有しない.実際のパラメータが形式パラメータと一致しない場合、先に強制的に変換されます.
  • 配列動作:配列オブジェクトが宣言されると、その識別子は本質的にその配列の開始アドレスを指すポインタである.配列はメモリに連続しています.配列のインスタンス化のいくつかの方法、下付きスケールと下付きスケールなし、以下に示す:
  •     int a[10]={0, 1, 2,3,4,5,6,7,8,9};  //a[0]-a[9];     ,     ,    ,      ,a       ,a      。
        int b[10] = {1,2,3,4};
        int c[] = {1,2,3,4,5,6};
        int d[3][4] = {1,2,3,4};//    ,               12 
        int e[][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; //       ,      ,     3
        int f[][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}}; //           
    

    カスタムオブジェクトの配列の場合は、実用的なオブジェクト配列を使用して配列を一括インスタンス化します.
    class D2{
    public:
        D2(int a){}; //         , D2 d[2]={1,2};     ,   D2 d[2];          ;
        ~D2(){};
    void print(){cout<<"haha"<<endl;};
    };
    int main(){
    D2 d[2]={1,2}; //           ,    ,    。
    };
    

    配列の遍歴:配列の変数名は本質的に配列を格納するメモリヘッダアドレスを指すポインタであり、配列を遍歴するには2つの方法があります.
    //    
    int a[2] = {1,2};
    for (int i=0;i<2;i++){
    cout<<a[i]<<endl;
    }
    //    
    int a[2] = {1,2};
    int *p = a; //a        
    for (int i=0;i<sizeof(a)/sizeof(int);i++){ // sizeof      
    	cout<<*p++<<endl; //*p++                      ;
    }
    

    特に、ポインタを呼び出すときに、カスタムオブジェクトのループが異なることを示します.
    class D2{
    public:
        D2(int a){}; //         , D2 d[2]={1,2};     ,   D2 d[2];          ;
        ~D2(){};
    void print(){cout<<"haha"<<endl;};
    };
    int main(){
        D2 d[2]={1,2};
        D2 *p = d;
        for (int i =0;i<(sizeof(d)/ sizeof(D2));i++){
            p++->print();
        }
    }
    
    //haha
    //haha
    

    皆さんは、上のポインタが前にないことに気づきましたか?これは、実際にpはポインタとしてD 2オブジェクトのメモリ空間を指し、ポインタは->演算子によってオブジェクトのメンバーメソッドにアクセスし、pはオブジェクト自体を指すためです.△では、*p.print()でもよろしいでしょうか.テストしてみましたが、できませんでした.原因は分かりません.
  • 参照タイプ:パラメータ双方向伝達を実現可能
  • void swap(int &a, int &b){
        int t;
        t = a;
        a = b;
        b = t;
    }
    int main(){
    	int a = 1;
    	int b = 2;
    	swap(a, b);
    	cout<<a<<','<<b<<endl;
    	//2,1
    }
    

    参照変数の作成(参照とポインタの区別に注意)
    int a = 1;
    int &ra = a; //     a   , a         ,   。
    
  • 関数のリロードは異なるパラメータテーブルを使用して関数を初期化し、関数のリロードを実現することができる:(静的マルチステートとも呼ばれる)
  • int add(int a, int b){
    	cout<<"int"<<endl;
        return a+b;
    }
    
    float add(float a, float b){
    	cout<<"float"<<endl;
        return a+b;
    }
    int main(){
    add(1,2);
    add((float)1.2, (float)2.3);
    return 0;
    };
    
    //int float
    
  • ポインタの使用:ポインタはC++が継承するCの特性の一つであり、メモリ空間を操作することができる.変数を定義するポインタ:
  • int i=0;
    int *p = &i; //*p            ,    ,               。
    cout<<*p<<endl;
    //0
    

    空のポインタを定義し、別のタイプのポインタに変換できます.
    void *pv;
    int *pint = static_cast<int *>(pv);
    

    定数のポインタと定数のポインタ:
    //     :
    int a;
    const int *p1 = &a; //p1        ,       
    int b;
    p1 = &b; // p1      ,      ;
    
    //    :
    int *const p2 = &a; //    ,     ,       
    
  • インライン関数は时には、関数が简単すぎて、私达は関数の前にinlineキーワードを加えることができて、コンパイラが関数を作成しないことを提案して、直接関数のコードをプログラムの中に置いて実行して、例えば:
  • inline int add(int a, int b){
        return a+b;
    }
    
  • テンプレート関数:abcの3つの数のサイズを比較するなど、さまざまなタイプのインポートと処理に使用できます.彼らはint全体でもdouble全体でもある可能性があります.そこで、テンプレート関数を利用して、1つの関数を書くだけでいいです.
  • template <typename T>
    T max_3(T x, T y, T z){
      if ((x>y) && (x>z)){
          return x;
      }
      if ((y>x) &&(y>z)){
          return y;
      }
      return z;
    };
    int main(){
    int  a=3,b=4,c=5,m;
        m=max_3(a,b,c);
        cout<<"The  max  value  of  "<<a<<",  "<<b<<"  and  "<<c<<"  is  "<<m<<endl;
        double  d=5.3,e=2.9,f=7.8,n;
        n=max_3(d,e,f);
        cout<<"The  max  value  of  "<<d<<",  "<<e<<"  and  "<<f<<"  is  "<<n<<endl;
        char  c1='b',c2='W',c3='6',c4;
        c4=max_3(c1,c2,c3);
        cout<<"The  max  value  of  '"<<c1<<"',  '"<<c2<<"'  and  '"<<c3<<"'  is  '"<<c4<<"'"<<endl;
        return  0;
    }
    
  • オブジェクト関連作成オブジェクト向け:
  • class object{};
    

    これが簡単なオブジェクトです.私たちは中にいくつかの方法を追加することができて、それぞれ異なる時に呼び出されて、最も基本的な2つは、構造方法と分析方法です.
    class object{
    public:
    object(){}; //    
    ~object(){}; //    
    };
    

    コンストラクションメソッドはオブジェクトの作成時に呼び出され、コンストラクションメソッドはオブジェクトの破棄時に呼び出されます.オブジェクトのライフサイクルが終了すると、破棄されます.手動で破棄する場合はdelete関数を使用します.
    class object{
    public:
    object(){}; //    
    ~object(){}; //    
    };
    int main(){
    	object o[2];
    	delete[] o; //        
    	object o;
    	delete o; //      
    };
    

    また、オブジェクトのコンストラクション関数も再ロードできます.関数のリロードは、形式パラメータテーブル、const宣言、パラメータタイプによって行うことができます.以下に、intが入力されると、第2の構造方法が呼び出され、入力されないのが第1の構造関数である.
    class object{
    public:
    int a = 0;
    object(){}; //    
    object(int a){this->a=a;};
    ~object(){}; //    
    };
    

    複製コンストラクタ:オブジェクトが実際のパラメータとして関数に入力されると、オブジェクトの複製コンストラクタが呼び出される特殊なコンストラクタです.
    class object{
    public:
    int a = a;
    object(){}; //    
    ~object(){}; //    
    object(const object &o){ //                 
            a = o.a;
            cout<<"    "<<endl;
        }
    };
    

    レプリケーションコンストラクション関数は宣言されない場合、デフォルトが割り当てられます.手動で実装すると、上記のconst object&oのようなコピーされるオブジェクトを表すオブジェクトの別名(定数)が受け入れられます.新しく生成されたオブジェクトは、古いオブジェクトのいくつかの属性を取得し、前の例ではaのように、構造関数のコピー方法で書きます.構造をコピーする例:
    class object{
    public:
    int a = a;
    object(){}; //    
    ~object(){}; //    
    object(const object &o){ //                 
            a = o.a;
            cout<<"    "<<endl;
        }
    };
    int main(){
    object o1;
    object o2(o1); // o1      o2;
    };
    

    次に、静的メンバー変数について説明します.静的メンバー変数の本質は、クラス内のすべてのオブジェクトが共有して維持する空間です.たとえば、次のようになります.
    class p{
    public:
        static int count; //      
        p(){
            count++; //      ,    
        }
        ~p(){
            count--;
        }
    };
    int p::count=0; //             ;
    int main(){
    	p p1,p2;
        cout<<p1.count<<endl;
        cout<<p2.count<<endl;
    };
    
    // 2
    // 2
    

    順方向参照宣言:aクラスがbクラスを呼び出し、bクラスもaクラスを呼び出す場合、どのクラスの定義を前に置くと、未定義のクラスが発生するため、順方向参照宣言を使用する必要があります.なお、詳細に定義されていない前に、クラスの詳細は使用できず、クラスのシンボルのみが使用され、インスタンス化することはできません.
    class line; //   
    .....//        line   ;
    class line{};//   
    

    常メンバー、常オブジェクト、常関数:
    class c{
    public:
        c(){};
        void print(){cout<<"print"<<endl;};
        void print() const{cout<<"print const"<<endl;}; //const           
    };
    int main(){
        c const c1;
        c c2;
        c1.print(); 
        c2.print(); 
        //print const
        //print
    }
    

    以上のように、クラスcには2つのメンバー関数があり、print関数は1回再ロードされ、constが追加され、常メンバー関数となる.main関数では、オブジェクトをインスタンス化するときにconstを加え、オブジェクトが通常のオブジェクトになります.通常のオブジェクトはメンバー関数としてのみ呼び出されます.常メンバー関数では、クラスのプロパティを変更できません.通常オブジェクトは、通常メンバー関数のみを呼び出すことができます.あるクラスを別のクラスのメンバーにするにはどうすればいいですか?答えはコンビネーションクラスを使用しています.以下のようにします.
    class object(){}
    class line{
    public:
        line(object o2):o(o2){ //     
            this->o=o2;
        }
    private:
        object o;
    };
    

    これによりobjectクラスオブジェクトo 2をlineクラスに組み合わせることができる.また、クラスには様々なリロードの特性があり、紙面に限られていますが、ここでは一つ一つ列挙しません.次のC++ノートでは、演算子のリロード、入出力のリロードなど、クラスの他のリロード特性について詳しく説明します.これらのリロードはpythonクラスの魔法メソッド(ダブルダウンメソッド)に似ており、カスタムクラスの操作と機能を改善しています.