const浅析
文書ディレクトリ前言 const 1. constについて: 2. constオブジェクト初期化 3. 最上位および最下位constコンセプト 4. constとリロード関数 5. constとクラスの定数メンバー関数 6. constとクラス 7. constとクラス静的メンバー 8. constとtypedef まとめ 前言
c++において
const
1.constについて: 初期化時に初期化対象が . は変更できません.参照オブジェクトのタイプは、参照オブジェクトのタイプと一致する必要があります 上記参照のルールのため、 のみである.参照タイプに対応する例外
修正 を見ることができます
2.constオブジェクトの初期化非参照ポインタの一般的なタイプは、付与動作 である.参照およびポインタ参照およびポインタは、同じタイプのオブジェクト のみを初期化する.
3.トップレベルと下位レベルのconst概念
最上位
実は私たちはずっと最上階のconstを使っています.例えば
覚えておいてください:
下位
もちろん、オブジェクトを最上位レベルと最下位レベルに変更できます.
最上位constがコピーされると、最上位constは無視されることに注意してください.
4.constとリロード関数
関数を再ロードする場合、
上から分かるように、最上位constは無視されるため、最上位constと他の最上位constは区別できない.
参照対象のタイプは同一である必要があるため、
下のconstは無視されず、下のconstは下のconstと区別されるため、下のconstはリロードに用いることができる.
5.constとクラスの定数メンバー関数
単純なクラスを定義する
ここで
しかし、上記の関数で変数の値を変更しなければならない場合があります.どうすればいいですか?c++には
6.constとクラス
クラスのインスタンス化を定義するときに、クラスのインスタンス化を
上記のエラーの原因は、caのタイプが
7.constとクラス静的メンバー
同様に上のクラスを例にとります
クラスで定義静的変数はクラスで初期化できず、クラス外で初期化しなければならない.上記はクラス外で
しかし、例外があります.
8.constとtypedef
ポインタを毎回定義したくない場合は、
同じ操作を行う
以上のようにすると、
なぜなら、
上記のtypedefで定義別名は、
まとめ
この節では、
c++において
const
に使用する箇所は多く、const
自体もポインタに対して最上位層と最下層層があるなど、異なるタイプに対して異なる意味を持つ可能性がある.本節はC++におけるconst
の異なる場所での異なる表現または意味について検討する.const
const
修飾オブジェクトは、定義時に初期化する必要があります.1.constについて:
const
修飾オブジェクトは、作成すると一般的には変更できないため、const
オブジェクトに対して初期化が必要となる.int i = 0;
const int j; // error.
const int j = 0;
const
であるか非const
であるかに関心がないint i = 0;
const int j = i; // i const
const
const
const int i = 0;
i = 1; // error const
int i = 0;
int &j = i;
double &size = j; // error. size j
const
のタイプの参照はdouble j = size;
のオブジェクト参照int i = 0;
const int &size = i;
int &j = size; // error. size const int, j int.
int size = 0;
const double &i = size; // size i , const
理由:iとsizeの両方のタイプが一致しないが、iを初期化するとコンパイラはsizeに一時量(const double &i = j )
)を生成し、そして、iが最終的にこの一時量にバインドする(const
.iが一時量にバインドできるのは、const
のオブジェクトが修正できないためであり、iは修正できず、一時量が変更されないことを保障する.実際に一時量にバインドされ、sizeにバインドされていないことに注意する.const
のオブジェクトの値int size = 0;
const double &i = size;
size = 1; // i , size
修飾のオブジェクトに対してのみ修正できないことを制限するため、オブジェクトが一定量であることを保証することはできないので、定数であることを保証できるオブジェクトはconstexpr
と定義することが望ましい.constexprに対してはっきりしないのはconstexprの浅い分析2.constオブジェクトの初期化
const
のオブジェクト像非const
のオブジェクトを用いる初期化を行う際には、参照やポインタのように初期化オブジェクトの種類が要求されることに注意が必要である.int i = 0;
const int size = i;
const int &j = i;
const_cast<int&>(size) = 1; // size 1
i = 2; // j i, i j
を直接行うことができるconst int i = 0;
int j = i;
3.トップレベルと下位レベルのconst概念
最上位
const
:ポインタ自体が定数である(すなわち、アドレスの変更は許されない).実は私たちはずっと最上階のconstを使っています.例えば
int i = 0;
です.これは最上階のconstです.iのアドレスは変わらないので、値だけが変わります.const int ci = 0;
const int *pi = &ci;
int &r = ci; // error
int *p = pi; // error
覚えておいてください:
const int i = 0
、ここのiも const
*です.下位
const
:ポインタが指すオブジェクトは定数である(ポインタ自体は修正可能であるが、指す値だけは修正できない).int size = 0, i = 0; // const
int *const p = &size; // const , const
p = &i; // error. p const
*p = 1; // const
もちろん、オブジェクトを最上位レベルと最下位レベルに変更できます.
int size = 0, i = 0;
const int * p = &size; // const , const
ptr = &i; // ptr , const
*ptr = 1; // error. const
最上位constがコピーされると、最上位constは無視されることに注意してください.
int size = 0;
const int * const p = &size; //
const int i = 0; //
4.constとリロード関数
関数を再ロードする場合、
const
型のパラメータは、最上位constと最下位constを処理する際に問題が発生する可能性がある.具体的にどんな問題を分析してからまとめますか.const int i = 0;
int size = i; // const
auto j = i; // auto j int , i const
上から分かるように、最上位constは無視されるため、最上位constと他の最上位constは区別できない.
void Ccount(int ccount) {} // ccount const
void Ccount(const int ccount) {} // error. ccount const, const,
void Ccount_pointer(int *ccount) {} // ccount const
void Ccount_pointer(int *const ccount) {} // error. ccount const, const,
参照対象のタイプは同一である必要があるため、
int &i
はconst int &i
と区別する、前者のタイプはint
、後者のタイプはconst int
であるため、後者は下位constである.下のconstは無視されず、下のconstは下のconstと区別されるため、下のconstはリロードに用いることができる.
5.constとクラスの定数メンバー関数
const
を関数名の前に置くとその意味はコンパイラの戻りタイプがconst
の定数であることを伝えるだけであるが、const
を関数名の後に置くとまた別の状況であり、ここで主に分析するのは状況である.// error. , , .
void const_reference(int i) {} // i const. int
void const_reference(int &i) {} // i const. int
//
void const_reference(int &i) {} // i const. int
void const_reference(const int &i) {} // i const. const int
void const_pointer(int *i) {} // const
void const_pointer(const int *i) {} // const
単純なクラスを定義する
const int const_func(int i) {return i;} // const ,
int const_func(int i) const {return i;} // error. const , ( ) , .
int const_func() const
の関数のconst
はコンパイラに教えるものであり、クラスで定義非静的変数は変更できない.なぜなら、クラスのすべてのメンバー関数がthis
に暗黙的に入力され、上記のメンバー関数がclass A {
private: int nun;
public: int const_func() const {return 0;} // success
};
//
int const_func() const { ++num; return 0;} // error
this
のポインタ自体が最上位のconstである、関数名の後ろに置かれたconstはthisポインタを修飾するためのものであるが、thisポインタが表示することができないため、constは関数名の後にしか置かない.ここで
const
が修飾this
であることが分かるので、this->i
は修正することができず、静的メンバはインスタンス化クラスそのものではなく、thisが静的変数を指すこともないので、以上のタイプの関数で静的変数を修正することができる.const
メンバー関数名の後ろに置かれた関数定数メンバー関数と呼びますしかし、上記の関数で変数の値を変更しなければならない場合があります.どうすればいいですか?c++には
mutable
のキーワードがあり、このような特例の発生を許容する.mutable
はコンパイラに教えるものであり、num
は任意の関数で修正することができる.int const_func(const A * const this) { ++num; return 0;}
6.constとクラス
クラスのインスタンス化を定義するときに、クラスのインスタンス化を
const
、すなわちclass A {
private: mutable int nun;
public: void const_func() const {++num;} // success
};
上記のエラーの原因は、caのタイプが
const
であるため、それに対応する関数は定数メンバー関数であるべきであるため、クラス関数の実装を定義する際に、定数メンバー関数を1つ再ロードすることが望ましい.7.constとクラス静的メンバー
同様に上のクラスを例にとります
class A {
private: int nun;
public: int const_func() {return 0;}
};
A a;
const A ca;
a.const_func(); // success
ca.const_func(); // error
クラスで定義静的変数はクラスで初期化できず、クラス外で初期化しなければならない.上記はクラス外で
int A::num = 0;
に変更すべきである.しかし、例外があります.
class A {
private: static int nun = 0; // error
public: int const_func() const {++num; return 0;} // success.
};
const
は、作成時に初期化する必要があることを要求するため、上記の例が成立する.8.constとtypedef
ポインタを毎回定義したくない場合は、
typedef
でポインタタイプを定義したいと考えています.次のようになります.class A {
private: const static int nun = 0; // success
};
同じ操作を行う
typedef char * Str;
char *str1 = "hello";
const char *str2 = "hello";
const Str str3 = "hello"; // gcc, g++ , vs17 , , , vs cl
以上のようにすると、
typedef
は単なる置換ではなく、str 2と同じではなくconst Str str3
に変換することが分かる.なぜなら、
char *const str3
が声明を書き換えると、実際のデータ型はchar *
ではなくchar
になり、逆にchar *
が声明子の一部になり、*
のデータ型はconst Str
になり、const char
が*
を修飾すると、定数ポインタになるからである.上記のtypedefで定義別名は、
const char
、例えばusing Type =
で置き換えることができる.またtypedefの代わりにusingを使用することを提案する、typedefの機能usingはすべてあり、またtypedefはテンプレート化機能をサポートしていない.その後、using Type = char *
の使用を推奨する理由を分析する.まとめ
この節では、
using
の用法に関する注意点の一部をまとめると、めまいがするように見えるかもしれないし、一度に覚えやすいわけではないので、見ているときにも検証したほうがいいと思います.最も主要に底層const
と最上階const
を覚えて、どのように重荷して、基本的に多くの問題はすべて派生します.