C++レビューのconstオブジェクト、constメンバー関数、mutableタイプ

3483 ワード

まずconstの一般的な使い方をまとめてみましょう.
1定数をconst定数と呼ぶ
        const int x = 100; 
2 constリファレンスと呼ばれるリファレンスを修飾するために使用されます.リファレンスが参照する変数の値を変更できないことを示します.
        const int &ref = x;
        int &ref2 = x;//Error,ref 2は定数ではなく,参照が指す変数xの値を修正することができるが,xは実際に定数であり,修正は許されないため論理的ではない,この用法は誤りである
3ポインタを修飾する場合、3つのケースがあります.
1つ目は、constが*の左側に表示され、(*ポインタ)が定数であることを示し、ポインタが変数であり、他の変数を指すことができます.以下のようにします.
        const int *p; 
2つ目は、constが*の右側に表示され、ポインタが定数であることを示し、ポインタは他の変数を指すことはできませんが、ポインタが指す変数の内容を以下のように変更することができます.
        int *const p = &x; 
第三に、constは*の左側にも*の右側にもあり、ポインタが定数であることを示し、ポインタが指す変数の内容も定数であり、以下のようにします.
        const int *const p = &x;
4クラス内のデータメンバーを修飾するために使用されます.constデータメンバーと呼ばれ、constデータメンバーの初期化はコンストラクション関数の初期化リストで行います.データ・メンバー定義時に直接初期化することはできません.
5クラスオブジェクトを修飾するために使用されます.constオブジェクトと呼ばれます.
        const Test t(10);
6クラスのメンバー関数を修飾するために使用されます.constメンバー関数と呼ばれます.これは、オブジェクトの状態を変更できないことを示します.つまり、データ・メンバー(Read Only)にのみアクセスでき、データ・メンバーを変更できないことを示します.
上記ではconstのすべての使い方をまとめましたが、ここでは、constがクラスのメンバー関数を修飾するために使用される場合、クラスのデータメンバーを変更することはできませんが、場合によってはクラスのデータメンバーを変更する必要がある場合、どうすればいいのでしょうか.このときmutableタイプの役割が発揮され、mutableの英語名は可変で、変化しやすく、すなわちそれによって修飾されたデータメンバーは、constメンバー関数でも非constメンバー関数でもアクセスできます.もちろん、static静的メンバー関数以外(静的メンバー関数にはthisポインタがないため、オブジェクトデータメンバーおよび関数にアクセスできません).これにより、constメンバー関数はクラス内のmutableで修飾されていないデータメンバーを変更することはできません.これらのデータメンバーに対してはread onlyしかありませんが、mutableで修飾されたデータメンバーをread/writeすることができます.いくつかの応用場面では比較的柔軟である.簡単な例を挙げて、これらの問題を説明します.
        
#include <iostream>
using namespace std;

class Test
{
public:
    Test(int x):x_(x), outputTimes_(0)
    {
    }

    //  Getx()           x    ,   const  ,   const    ,            
    int Getx() const
    {
        //x_ = 100 ;// Error, const              
        cout << "const Getx..."<< endl;
        return x_;
    }

    // const       const        
    int Getx()  // const const            
    {
        cout << "Getx..."<<endl;
        return x_;
    }

    int Setx()
    {
        return x_;
    }


    void Output() const 
    {
        //x_ = 102; //Error,     mutable    
        cout << "x = "<< x_ << endl;
        outputTimes_++; //    mutable       
    }
    
    int GetOutputTimes() const
    {
        return outputTimes_;
    }

private:
    int x_;
    mutable int outputTimes_; //mutable    
    
};

int main()
{
    //const  ,     ,         ,       
    const Test t(10);
    t.Getx(); //  : int Getx() const   , const        const Getx()     
   
    //t.Setx(); //Error,    , const      const    ,   :const     ,            ,  const                ,                     ,const       const    ,     const    ,  const               ,      。

    Test t2(20);
    t2.Getx(); //     const Getx,  t2     ,  const  
    t2.Output(); //        const    ,       const    ,      const     
    t2.Output(); //     ,outputTimes_ 1,    mutable       ,   const        

    cout << "outputTimes= "<< t2.GetOutputTimes() << endl; 

    return 0;
}

ここで注意しなければならないのは、constオブジェクトがオブジェクトの状態を変更できないため、constオブジェクトはconstメンバー関数のみを呼び出し、通常のオブジェクトは任意のメンバー関数を呼び出すことができることです.またconstオブジェクトは宣言時に初期化されます.これはconstが変更した変数と一致し、const int x=100などである.クラスに同じ名前の関数が2つ定義され、そのうちの1つはconstで修飾され、もう1つはconstで修飾されず、それらの間にはリロードが構成されています.この場合、constオブジェクトはconstメンバー関数を呼び出し、通常のオブジェクトはconstメンバー関数ではなくconstメンバー関数を呼び出します.