C++:const

5467 ワード

const constはC++が提供する強力なキーワードであり、constの使い方は非常に多いが、総じて言えば、constの役割は1つしかない:修飾された内容がプログラムによって修正されないことを保証する.
const基本用法
1つのタイプのオブジェクトに対してconst修飾を使用すると、すなわち、このオブジェクトが読み取り専用であり、修正操作ができないことが制限され、修正操作ができないため、constオブジェクトを宣言する際に同時に値を付与または初期化する必要がある.constオブジェクトの初期化は一般的に次の形式です.
const TypeName Var = Expression;

例:
const int a = 0;
int const a = 0; //     
a = 1; //     

なお、constオブジェクトの初期化は式で初期化されますが、私たちの例では定数式が使用されています.実際、const初期化は次の形式で行うことができます.
int getA() {
    return 0;
}
const int a = 0; //    0      ,        ,a         
const int b = getA(); // getA()      ,b       

1つの特殊な状況は、このconstオブジェクトがグローバル役割ドメインに存在することを望む場合、宣言時にextern修飾を加えることができ、宣言時に初期値を付与しないことができるが、プログラムが少なくとも1つの宣言初期値を有することを保証しなければならない.
// A.cpp
extern const int a;

// B.cpp
extern const int a = 0;

constリファレンス
constリファレンスはconstオブジェクトへのリファレンスです.つまり、リファレンスの内容がconstオブジェクトであるかどうかに関係なく、リファレンスの内容が変更されないことを確認します.
int a = 0;
const int b = 0;
const int &c = a; //   ,      a  ,     c  a
const int &d = b; //   ,b、d     

constリファレンスを一時オブジェクトにバインドするのは違法であることに注意してください.
int a = 0;
const int &b = a + 1; //   a+1         
//   
const int temp1 = a + 1;
const int &b = temp1;

const double &c = a; //                  
//    
const double temp = a;
const double &c = temp;

コンパイルは可能ですが、これは意味のない参照バインドです.
constとポインタ
constはポインタを修飾することもできます.マルチレベルポインタの存在によりconstの結合も複雑になる.
int a = 0;
const int b = 0;

const int *c = &a; //   ,c          ,  a      
//    
int const *c = &a;

const int *d = &b; //   ,b   ,c        
int *e = &b; //   ,b   ,            
const int *f = &b; //   ,b   ,f        

最も一般的なのは定数ポインタと定数を指すポインタであり、前者はポインタが定数であることを示し、すなわち指向するアドレスは変更できないことを示し、後者は指向するアドレスに格納されている内容が定数であることを示す.定数ポインタと定数を指すポインタはconstで修飾された1級ポインタの2つの場合で、『C++Primer』という本では、両者をそれぞれ最上位constと最上位constと呼ぶ.
const int a = 0;
const int *b = &a; // b        ,  const
int c = 0;
int * const d = &c; // d       ,  const
const int * const e = &a; // e            

マルチレベルポインタに関連する場合、宣言式を右から左に読み、constがどのレベルを修飾しているかを確認することができます.
int a = 0;
int *b = &a; // b       
int **c = &b; // c       
int **const *d = &c; // d       
/* 
         :
1.         d
2.    *,  d     ,        
3.   const,              
4.      *,             
5.      *,                  
6.   int,              int     
                        
*/
d = &c; //   ,d       
*d = &b; //   ,   d          
**d = &a; //   ,     d          

constexpr式
前述したように、constオブジェクトは定数式または非常量式で初期化できます.定数式とは,コンパイル期間中に結果が得られる式であり,定数式から初期化されたconstオブジェクトが定数式の構成に関与してもよい.ある場合、1つの式がコンパイル期間中に決定されることを望んでいますが、複雑なプロジェクトで1つのオブジェクトが定数式であるかどうかを確認することは非常に困難であり、C++はconstexprキーワードを導入し、あるオブジェクトが定数式であることを明示的に説明します.
constexpr int a = 0; //   ,    0        
constexpr int b = getB(); //        getB()        

コンパイル期間中にconstexprオブジェクトの値を決定する必要があるため、ポインタと参照constexprの初期化にはより厳しい要求があります.一般的に、関数内に定義されたオブジェクトアドレスはコンパイル期間中に決定できないため、初期化定数式の値としては使用できません.逆に、グローバルオブジェクトは使用できます.
constと関数constは、関数のパラメータを修飾することができる.
int LiF(const int lif);
//   ,         lif
//   ,          ,                     
int LiF(const int *lif);
//   ,         
int LiF(const int &lif);
//   ,        ,        
constはまた、関数の戻り値を修飾することもできる.constは、関数の戻り値が変更されないこと、すなわち左の値として使用できないことを保証する.
const int& LiF(int &lif) {
    return lif;
}

constとクラスconstはクラスのメンバーを修飾することができ、コンストラクション関数を呼び出すとオブジェクトの内容が確認されるため、すなわちconstメンバーはコンストラクション関数の前に初期化する必要があり、修飾されたクラスメンバーは初期化リストでのみ初期化される.
class LiF {
public:
    LiF(int _lif): lif(_lif) {}
private:
    const int lif;
};

constはクラスのメンバー関数を修飾することができ、修飾されたメンバー関数を常メンバー関数と呼び、常メンバー関数をすべてのオブジェクトで呼び出すことができますが、常オブジェクトは常メンバー関数のみを呼び出すことができます.これは、メンバー関数のパラメータリストには、thisポインタが暗黙的に渡され、constでメンバー関数が修飾され、実際にはthisが修飾され、const *は通常のポインタタイプに変換できないため、通常のメンバー関数を呼び出すことができないためである.また、関数リロードは下位constを無視しないため、メンバー関数のconstに基づいてリロードを構成してもよい.非常に正確な一致によって通常のメンバー関数が見つかり、通常のオブジェクトは対応する通常のメンバー関数に一致します.
class LiF {
public:
    int get() { return lif; }
    int get() const { return lif; } //        
private:
    int lif;
};

LiF l1;
const LiF l2;
l1.get(); //     int get();
l2.get(); //     int get() const;

クラスのメンバーがconstオブジェクト内でも情報を記録することを望む場合があります.この場合、C++はmutableキーワードを提供する永遠に可変なメンバーが必要である.
class LiF {
public:
    void count() const {
        lif++;
    }
private:
    mutable int lif;
};

LiF l1;
const LiF l2 = l1;
l2.count();
constはまた、メンバー関数の戻り値を修飾し、通常の関数のconst戻り値と同様にチェーン呼び出しを禁止したり、戻り値が左になったりすることを禁止することもできる.
class LiF {
public:
    const LiF& operator= (const LiF &l) {
        lif = l.lif;
        return *this;
    }
    const LiF& set(int _lif) {
        lif = _lif;
        return *this;
    }
private:
    int lif;
};

LiF l1, l2, l3;
l1 = l2 = l3; //   
(l1 = l2) = l3; //   ,               ,      

LiF l4;
l4.set(1); //   
l4.set(1).set(2); //   ,set(1)        this