C++言語体系設計哲学のいくつかの随想(未完待続)
4143 ワード
静的タイプ言語では、データを適切に操作し、所望の値を得ることが本質的な目標である.具体的には、次のことが必要です.
(1)データ型の定義
あなたが定義したデータは何ですか.整形ですか、浮動小数点ですか、文字ですか.このタイプのデータに含まれる値の範囲は何ですか.
(2)操作の意味の定義
操作は厳格なデータ型に関連しています.操作は、特定のタイプのデータに対して、操作を実行した後にどのような結果が得られるかを示します.
===========================================
C++は典型的な静的タイプ言語である.C++では、「データ型」でも「操作」でも、内蔵とカスタムに分けられます.
C++の組み込みデータ型は次のとおりです.
(1)基本内蔵タイプ
整形、浮動小数点、ブール、文字....
(2)STLライブラリ定義のタイプ
例えばよく使われるiostream、string、反復器......
さらにC++は、すべてのタイプの参照、ポインタ、配列を含む複合タイプメカニズムを定義し、完全なデータ型の一部とすることができます.
ちなみに最上階/下層const、static、volatile...などの修飾子は、データの他の属性を定義し、これらの属性は完全なデータ型の構成部分であってもよい.
カスタムタイプでは、class、struct、union定義、関数署名が最も一般的です.もちろん、複合タイプメカニズムを使用して自分のクラスの参照、ポインタ、配列などを定義することもできます.
==============================
ポイントは、変数でも定数でも、特定のデータ型に属する必要があることです.操作は正確なデータ型に基づいてのみ定義されるため(コンパイル原理では「意味」と呼ばれます).すなわち、決定されたオペレーションセット(例えばC++言語に組み込まれたすべてのオペレーション)では、1つの変数にデータ型が割り当てられている限り、この変数が実行できるオペレーションも決定される.変数nValをintタイプとして定義すると、nValは加減乗除、関係演算、コピー、doubleへの変換、関数パラメータへの伝達、配列としての下付き記号に参加できます.
C++の「操作」は、その意味が非常に広い.実はC++言語はすでにメンバー関数、オペレータのリロード、関数のリロード、関数の定義の暗黙的なタイプを構築することによって変換されました...などのメカニズムは,C++が静的タイプ言語としての本質を示している:特定のタイプのデータに属し,その上の操作を加えている.このように理解することができて、いかなる1つの操作、本質は関数で、オペレータはC++言語の内部でも関数として扱われます(これもC++がoperatorオペレータのリロードメカニズムを提供する動機を説明することができます);クラスのメンバー関数、メタ関数も、クラス自体という「データ型」に対する操作です.
さらに、操作自体も特殊なデータ型です.関数のポインタ、関数の配列を定義でき、メンバーアクセス(->*,.*)は、データ型として使用できる機会が少なく、言語自体に制限されています.
C++の組み込み操作はよく理解できませんが、実際に私たちがよく使う言語メカニズムはすべて「操作」で、具体的には:
(1)さまざまなオペレータ
算術オペレータ、リレーショナルオペレータ、ビット演算、アドレス取得、単眼演算、逆参照、配列要素アクセス.....
(2)コピー操作
コピー初期化、リスト初期化(C++11)、代入演算、関数パラメータ、関数戻り値、型変換実行の一時変数コピー…その他の非参照シーン
(3)データ型変換
タイプ変換も操作です.通常の操作では、実行前に操作するデータのタイプを一致させる必要があります.現実的には、コードにタイプが厳密に一致するデータを提供することを保証することはできません.そのため、タイプ変換もC++言語の非常に一般的な操作です.
このような操作をどのように理解すればいいのでしょうか.たとえば、次のようになります.
上記のコードの最後の行の加算操作は、タイプのアップグレードを実行します.コンパイラの観点から、変数のクラスが新しく一致するタイプ(double)と同じである匿名の変数が生成され、intからdoubleへのタイプ変換操作が実行され、操作結果がこの匿名変数に保存されます.「+」操作は後で実行されます.すなわち,オペレーションが選択されると,いくつかのデータ型が完全に一致するオペレーション数が期待され,この条件を満たすためにタイプ変換が実行される.
割り当て操作では、=右のオペランドのデータ型が左と完全に一致することが期待され、この場合も上記と同様に匿名変数が生成され、タイプ変換が実行されます.準備作業が完了したら、==操作を実行します.
関数の呼び出しも、実パラメータタイプとパラメータタイプのマッチングという同じ原理に基づいている.
... ...
C++言語の内部には異常に複雑なタイプ変換規則(操作)が定義されているが,ほとんどは使用者に対して透明である.例:
整形アップ-char、short、boolは先にintに変換されます.
タイプアップ-精度損失を防止する;
タイプの減少-コピー操作でよく見られる精度の損失があります.コピー操作は、ソースオブジェクトをターゲットオブジェクトに厳密に一致させるため、算術操作の「整形アップグレード」はありません.コピーには、コピー初期化、値付け演算、関数呼び出しの実パラメータが含まれます.
非bool値はboolに変換でき、逆に0/1に変換されます.
任意のクラスの新しいポインタはvoid*に変換できます.
配列はdecltype、sizeof、typeid、アドレス&に使用されない場合、最初の要素を指すポインタに自動的に変換されます.
非下位constから下位constへの変換-定数への参照とポインタは非常量にバインドでき、内蔵タイプのアップグレードと低下とは異なり、下位constから非下位constへの変換は違法である.
サブクラスからベースクラスへの変換-ベースクラスポインタ/参照は、マルチステートの基礎となるサブクラスを指すことができます.下位constと同様に、逆の変換は不正です.
... ...
-
PS:下位constと継承システムタイプ変換の一方向性について:
本質的には、実行可能な操作のセットが小さいほど、参照/バインド可能なオブジェクトタイプが広がるデータのデータ型です.例:
データ型Aは、operA-operZの計26の操作を実行できます.データクラスの新しいBは、operH-operNなどのAのサブセットで実行できる.したがって、Bの参照/ポインタはAにバインドされてもよく(Bの参照/ポインタはA/Aのポインタ付与を受け入れることができる)、逆に不正である.
const int*は指向するintを変更することはできませんが、int*は可能です.つまり、データ型const int*の操作範囲はint*よりも小さいので、const int*はint*が指向するオブジェクトにバインドできます(本質的にはconst int*がint*の付与を受け入れることができることを意味します).継承システムでは、ベースクラスの操作範囲はサブクラスより小さいに違いないので、ベースクラスポインタは/ベースクラスがサブクラスを参照する合法的なものを指します.
このすべての原因は、コンパイラが静的タイプ言語に対して、オブジェクトが実際に指向しているタイプにかかわらず、その静的宣言タイプに従って、操作が合法かどうかを決定するために、常に「頑固」に、「独善的」に、その静的宣言タイプに従って決定することにある.コンパイラは、int*によってこのintを変更することができ、このint*が実際にconst intを指しているかどうかにかかわらず、下位constから非下位constへの変換を許可すれば、衝突をもたらすと「独りよがり」に考えられる.
-
PS:この観点に基づいてリロードを理解する
関数のリロード、オペレータのリロードの本質は、同じ名前で複数の操作を定義することです.その結果、コンパイルフェーズにおいて、特定のオペレーションを決定するプロセスが導入され、候補オペレーションから最も一致するオペレーションが選択される.上記の「タイプ変換」操作は、実行フェーズで行われます.
カスタマイズされた操作には、一般的な関数、メンバー関数、リロードされたオペレータ、コンストラクション関数定義の暗黙的なタイプ変換、コンストラクション関数定義のコピー操作が含まれます.
未完待機
(1)データ型の定義
あなたが定義したデータは何ですか.整形ですか、浮動小数点ですか、文字ですか.このタイプのデータに含まれる値の範囲は何ですか.
(2)操作の意味の定義
操作は厳格なデータ型に関連しています.操作は、特定のタイプのデータに対して、操作を実行した後にどのような結果が得られるかを示します.
===========================================
C++は典型的な静的タイプ言語である.C++では、「データ型」でも「操作」でも、内蔵とカスタムに分けられます.
C++の組み込みデータ型は次のとおりです.
(1)基本内蔵タイプ
整形、浮動小数点、ブール、文字....
(2)STLライブラリ定義のタイプ
例えばよく使われるiostream、string、反復器......
さらにC++は、すべてのタイプの参照、ポインタ、配列を含む複合タイプメカニズムを定義し、完全なデータ型の一部とすることができます.
ちなみに最上階/下層const、static、volatile...などの修飾子は、データの他の属性を定義し、これらの属性は完全なデータ型の構成部分であってもよい.
カスタムタイプでは、class、struct、union定義、関数署名が最も一般的です.もちろん、複合タイプメカニズムを使用して自分のクラスの参照、ポインタ、配列などを定義することもできます.
==============================
ポイントは、変数でも定数でも、特定のデータ型に属する必要があることです.操作は正確なデータ型に基づいてのみ定義されるため(コンパイル原理では「意味」と呼ばれます).すなわち、決定されたオペレーションセット(例えばC++言語に組み込まれたすべてのオペレーション)では、1つの変数にデータ型が割り当てられている限り、この変数が実行できるオペレーションも決定される.変数nValをintタイプとして定義すると、nValは加減乗除、関係演算、コピー、doubleへの変換、関数パラメータへの伝達、配列としての下付き記号に参加できます.
C++の「操作」は、その意味が非常に広い.実はC++言語はすでにメンバー関数、オペレータのリロード、関数のリロード、関数の定義の暗黙的なタイプを構築することによって変換されました...などのメカニズムは,C++が静的タイプ言語としての本質を示している:特定のタイプのデータに属し,その上の操作を加えている.このように理解することができて、いかなる1つの操作、本質は関数で、オペレータはC++言語の内部でも関数として扱われます(これもC++がoperatorオペレータのリロードメカニズムを提供する動機を説明することができます);クラスのメンバー関数、メタ関数も、クラス自体という「データ型」に対する操作です.
さらに、操作自体も特殊なデータ型です.関数のポインタ、関数の配列を定義でき、メンバーアクセス(->*,.*)は、データ型として使用できる機会が少なく、言語自体に制限されています.
C++の組み込み操作はよく理解できませんが、実際に私たちがよく使う言語メカニズムはすべて「操作」で、具体的には:
(1)さまざまなオペレータ
算術オペレータ、リレーショナルオペレータ、ビット演算、アドレス取得、単眼演算、逆参照、配列要素アクセス.....
(2)コピー操作
コピー初期化、リスト初期化(C++11)、代入演算、関数パラメータ、関数戻り値、型変換実行の一時変数コピー…その他の非参照シーン
(3)データ型変換
タイプ変換も操作です.通常の操作では、実行前に操作するデータのタイプを一致させる必要があります.現実的には、コードにタイプが厳密に一致するデータを提供することを保証することはできません.そのため、タイプ変換もC++言語の非常に一般的な操作です.
このような操作をどのように理解すればいいのでしょうか.たとえば、次のようになります.
int nVal = 42;
double fVal = 3.14;
double fValTwo;
fValTwo = fVal + nVal ; // nVal double
上記のコードの最後の行の加算操作は、タイプのアップグレードを実行します.コンパイラの観点から、変数のクラスが新しく一致するタイプ(double)と同じである匿名の変数が生成され、intからdoubleへのタイプ変換操作が実行され、操作結果がこの匿名変数に保存されます.「+」操作は後で実行されます.すなわち,オペレーションが選択されると,いくつかのデータ型が完全に一致するオペレーション数が期待され,この条件を満たすためにタイプ変換が実行される.
割り当て操作では、=右のオペランドのデータ型が左と完全に一致することが期待され、この場合も上記と同様に匿名変数が生成され、タイプ変換が実行されます.準備作業が完了したら、==操作を実行します.
関数の呼び出しも、実パラメータタイプとパラメータタイプのマッチングという同じ原理に基づいている.
... ...
C++言語の内部には異常に複雑なタイプ変換規則(操作)が定義されているが,ほとんどは使用者に対して透明である.例:
整形アップ-char、short、boolは先にintに変換されます.
タイプアップ-精度損失を防止する;
タイプの減少-コピー操作でよく見られる精度の損失があります.コピー操作は、ソースオブジェクトをターゲットオブジェクトに厳密に一致させるため、算術操作の「整形アップグレード」はありません.コピーには、コピー初期化、値付け演算、関数呼び出しの実パラメータが含まれます.
非bool値はboolに変換でき、逆に0/1に変換されます.
任意のクラスの新しいポインタはvoid*に変換できます.
配列はdecltype、sizeof、typeid、アドレス&に使用されない場合、最初の要素を指すポインタに自動的に変換されます.
非下位constから下位constへの変換-定数への参照とポインタは非常量にバインドでき、内蔵タイプのアップグレードと低下とは異なり、下位constから非下位constへの変換は違法である.
サブクラスからベースクラスへの変換-ベースクラスポインタ/参照は、マルチステートの基礎となるサブクラスを指すことができます.下位constと同様に、逆の変換は不正です.
... ...
-
PS:下位constと継承システムタイプ変換の一方向性について:
本質的には、実行可能な操作のセットが小さいほど、参照/バインド可能なオブジェクトタイプが広がるデータのデータ型です.例:
データ型Aは、operA-operZの計26の操作を実行できます.データクラスの新しいBは、operH-operNなどのAのサブセットで実行できる.したがって、Bの参照/ポインタはAにバインドされてもよく(Bの参照/ポインタはA/Aのポインタ付与を受け入れることができる)、逆に不正である.
const int*は指向するintを変更することはできませんが、int*は可能です.つまり、データ型const int*の操作範囲はint*よりも小さいので、const int*はint*が指向するオブジェクトにバインドできます(本質的にはconst int*がint*の付与を受け入れることができることを意味します).継承システムでは、ベースクラスの操作範囲はサブクラスより小さいに違いないので、ベースクラスポインタは/ベースクラスがサブクラスを参照する合法的なものを指します.
このすべての原因は、コンパイラが静的タイプ言語に対して、オブジェクトが実際に指向しているタイプにかかわらず、その静的宣言タイプに従って、操作が合法かどうかを決定するために、常に「頑固」に、「独善的」に、その静的宣言タイプに従って決定することにある.コンパイラは、int*によってこのintを変更することができ、このint*が実際にconst intを指しているかどうかにかかわらず、下位constから非下位constへの変換を許可すれば、衝突をもたらすと「独りよがり」に考えられる.
-
PS:この観点に基づいてリロードを理解する
関数のリロード、オペレータのリロードの本質は、同じ名前で複数の操作を定義することです.その結果、コンパイルフェーズにおいて、特定のオペレーションを決定するプロセスが導入され、候補オペレーションから最も一致するオペレーションが選択される.上記の「タイプ変換」操作は、実行フェーズで行われます.
カスタマイズされた操作には、一般的な関数、メンバー関数、リロードされたオペレータ、コンストラクション関数定義の暗黙的なタイプ変換、コンストラクション関数定義のコピー操作が含まれます.
未完待機