C++入門の基礎(10,000語徹底解説!!!)

序文

  C 言語は構造化されたモジュール言語であり、小規模なプログラムの処理に適しています。高度な抽象化とモデリングを必要とする複雑な問題や大規模なプログラムには、C 言語は適していません。ソフトウェア危機を解決するために、1980年代にコンピュータ業界はOOP(オブジェクト指向プログラミング:オブジェクト指向)という考え方を提唱し、時代の要請に応じてオブジェクト指向プログラミングをサポートするプログラミング言語が登場しました。
  1982 年、Bjarne Stroustrup 博士は、C 言語に基づいてオブジェクト指向の概念を導入および拡張し、新しいプログラミング言語を発明しました。C言語との起源関係を表現するためにC++と名付けられています。したがって、 C++ は C 言語をベースにして作成されており、C 言語の手続き型プログラミングだけでなく、抽象データ型を特徴とするオブジェクトベースのプログラミングや、オブジェクト指向プログラミングも実行できます。

ステージ コンテンツ
C とクラス クラスと派生クラス、パブリック メンバーとプライベート メンバー、クラスの構築と破棄、フレンド、インライン関数、代入演算子のオーバーロードなど。
C++1.0 仮想関数の概念、関数と演算子のオーバーロード、参照、定数などを追加します。
C++2.0 オブジェクト指向、新しい保護メンバー、多重継承、オブジェクトの初期化、抽象クラス、静的メンバー、const メンバー関数のより完全なサポート
C++3.0 更なる改善、テンプレートの導入、多重継承による曖昧さの問題の解決、対応する構築と破棄への対応
C++98 C++ 標準の最初のバージョンは、ほとんどのコンパイラでサポートされており、国際標準化機構 (ISO) と米国標準協会によって承認されており、C++ 標準ライブラリをテンプレート方式で書き直し、STL (標準テンプレート ライブラリ) を導入しています。
C++03 C++ 標準の 2 番目のバージョンでは、主にエラーの改訂、異質性の削減など、言語機能に大きな変更はありません。
C++05 C++ 標準委員会は、正式に C++0x という名前に変更された集計レポート (テクニカル レポート、TR1) をリリースしました。つまり、今世紀最初の 10 年間のどこかでリリースされる予定です。
C++11 C++ をより新しい言語に近づけるために、正規表現、範囲ベースの for ループ、自動キーワード、新しいコンテナー、リストの初期化、標準スレッド ライブラリなどの多くの機能が追加されました。
C++14 C++11 への拡張は主に、汎用ラムダ式、自動戻り値の型推論、バイナリ リテラル定数などの C++11 のバグと改善を修正することです。
C++17 C++11 でいくつかの小さな改善が行われ、19 個の新機能が追加されました。たとえば、static_assert() テキスト情報はオプションです。変数テンプレートに Fold 式が使用されます。if ステートメントと switch ステートメントの初期化子など。
C++20 C++11 以来最大のリリースで、モジュール (Modules)、コルーチン (Coroutines)、範囲 (Ranges)、コンセプト (Constraints) およびその他の主要な機能、および既存の機能などの多くの新機能が導入されています。 , Lambda はテンプレート、サポートの初期化などのスコープをサポートします。
C++23 定式化する

1. C++ キーワード

  これらはすべて C++ のキーワードであり、それぞれに特別な意味がありますが、ここで 1 つずつ説明するのは面倒でわかりにくいので、後ほど詳しく説明します。
ここに画像の説明を挿入

2. 名前空間

  C/C++ では、後で学習する変数、関数、クラスが多数あり、これらの変数、関数、クラスの名前はすべてグローバル スコープ内に存在するため、多くの競合が発生する可能性があります。名前空間を使用する目的は、名前の競合や名前汚染を避けるために識別子の名前をローカライズすることです。名前空間キーワードの出現は、この種の問題を目的としています。
  たとえば、<stdlib.h> には、乱数を生成するために使用される関数 rand() があります。
ここに画像の説明を挿入
  この時点で、<stdlib.h> ヘッダー ファイルがなくても正常に実行できることがわかります。ヘッダー ファイルがインクルードされた後に何が起こるかを見てみましょう。
ここに画像の説明を挿入
  コンパイルが失敗したことがわかりました。これは、ヘッダー ファイルの内容がコンパイル中に展開され、rand() 関数が定義したグローバル変数 rand と同じ名前を持つため、再定義されるためです。それに応じてスペースが作成され、その機能はこれが起こらないようにすることです。
  名前空間では、namespace キーワードを使用して名前と中括弧を追加します。ただし、出力行に WY : : rand と記述していることがわかります。これは、ヘッダー ファイルで rand を使用するのではなく、WY 名前空間で rand を出力することを意味します。
ここに画像の説明を挿入
  名前空間は、同じ名前の変数を異なる空間に区切る見えない壁のようなもので、必要な空間で変数を見つけることができます。しかし、名前空間内で同じ名前の変数はどうなるでしょうか? C++ の作成者は、この問題をすでに考えていました。つまり、名前空間は、一般に入れ子人形として知られる名前空間内で開くこともできるということです。
ここに画像の説明を挿入
  名前空間では、変数、関数、および型を定義できます。ただし、構造体の型を定義する場合は、アクセス時に構造体型にアクセスする必要があることに注意してください。構造体の後ろに書かれた。同時に同じプロジェクト内では同じ名前の名前空間が許可され、コンパイラはコンパイル時にそれらを自動的にマージします。

int rand = 0;//全局变量
namespace WY
{
    
    
	int rand = 1;

	int Add(int a, int b)
	{
    
    
		return a + b;
	}

	struct Node
	{
    
    
		int data;
		int* next;
	};
}
int main()
{
    
    
  //域作用限定符
	printf("%d", rand);
	printf("%d", WY::rand);
	printf("%d", WY::Add(1,2));
	struct WY::Node node;

	return 0;
}

  以前は、まだ一部の環境をシミュレートするために C 音声が使用されていましたが、C++ 自体はどのようなものなのでしょうか? C++ には独自の名前空間とヘッダー ファイルがあります。

//C++标准库的命名空间,将标准库的定义与实现都放入了这个命名空间中
#include<iostream>
using namespace std;
int main()
{
    
    
	cout << "Wang You" << endl;
}

  ただし、この書き方では、名前空間内のすべてのコンテンツが展開されるため、再定義の問題が非常に簡単に発生します。たとえば、他の人と一緒にプロジェクトを書くとき、同じ変数名を使用すると、その結果は、それを一緒に実行すると次のようになります。すべてが独自の名前空間を拡張するため、再定義は行われないのでしょうか? したがって、この書き方は、他の人と一緒に仕事をする場合はお勧めできませんが、自分自身の日常の練習では問題ありません, 結局のところ、変数名はそれ自体で制御されるため、この状況は回避できます。
  同時に、拡張は完全拡張または部分拡張も可能で、たとえば、Add 関数を頻繁に使用する必要がある場合は、スコープ修飾子 ( : : ) を追加する必要がないように部分拡張することができます。毎回使用する前に。

//全部展开
using namespace WY;

//部分展开
using WY::Add;

3. C++ の入出力

  実際、これは上に一度書いたものです。以下を参照してください。

#include<iostream>
using namespace std;
int main()
{
    
    
	int a;
	cin >> a;
	cout << "Wang You" << endl;
	return 0;
}

出力には C 言語の printf と同じ機能を持つ cout と、scanf と同じ機能を持つ cin が使用されます。

C言語と比較して注意すべき点は、

  1. cout 標準出力オブジェクト (コンソール) および cin 標準入力オブジェクト (キーボード) を使用する場合は、<iostream> ヘッダー ファイルをインクルードし、名前空間の使用法によって std を使用する必要があります。
  2. cout と cin はグローバル ストリーム オブジェクトであり、endl は改行出力を表す特別な C++ シンボルであり、これらはすべて <iostream> ヘッダー ファイルに含まれています。
  3. <<はストリーム挿入演算子です。>>ストリーム抽出演算子です。
  4. C++ の入出力を使用する方が便利で、printf/scanf の入出力のように形式を手動で制御する必要がありません。C++ の入力と出力では、変数の型を自動的に識別できます。
  5. 実際、cout と cin は、それぞれ ostream と istream 型のオブジェクトです。>> と << には、後で説明する演算子のオーバーロードやその他の知識も含まれるため、ここではそれらの使用法を簡単に検討します。

名前空間 std を拡張すると、標準ライブラリが完全に公開されるため、ライブラリと同じ名前の型/オブジェクト/関数を定義すると競合が発生します。この問題は日常業務ではほとんど発生しませんが、プロジェクト開発などでコード数が多く大規模な場合に発生しやすくなります。したがって、std::cout のように使用する場合は、名前空間を指定し、std::cout を使用して共通ライブラリ オブジェクト/型を拡張して、プロジェクト開発で使用することをお勧めします。

4. デフォルトパラメータ

  デフォルトパラメータは、関数の宣言または定義時に関数のパラメータのデフォルト値を指定します。関数を呼び出すとき、実パラメータが指定されていない場合は仮パラメータのデフォルト値が採用され、それ以外の場合は指定された実パラメータが使用されます。
ここに画像の説明を挿入
  一般に、関数を呼び出すときは、関数にパラメータを渡します。デフォルト パラメータの意味は、関数にパラメータを渡さない場合、デフォルトで設定したデフォルト パラメータ (int a = 0) を自動的に渡すことです。

4.1 全缺省

void fun(int a = 10, int b = 20, int c = 30)
{
    
    
	cout << a << " ";
	cout << b << " ";
	cout << c << " ";
	cout << endl;
}

ここに画像の説明を挿入
  このことからもわかりますデフォルトパラメータは右から左に指定する必要がありますしたがって、指定するパラメータは左から右であり、左側のデータは表示して渡すことができ、右側のデータはデフォルトのパラメータを使用できます。

4.2 セミデフォルト

  次に、セミデフォルトをもう一度見てみましょう。名前が示すように、デフォルト値を持つのは一部のみです。

void fun(int a,int b,int c = 30)
{
    
    
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

ここに画像の説明を挿入

知らせ:

  1. 準デフォルトのパラメータは右から左に順番に指定する必要があり、交互に指定することはできません。
  2. デフォルトパラメータは関数宣言と定義の両方に使用できません
  3. デフォルト値は定数またはグローバル変数である必要があります
  4. C言語はサポートしていません(コンパイラはサポートしていません)

  異なる宣言と定義が同時に表示されるのは、定義で指定されたデフォルト パラメータが宣言で指定されたデフォルト パラメータと異なる場合、コンパイラはそれらを区別できないため、デフォルト パラメータ (デフォルト パラメータ) はすべて定義で指定されます。

5. 関数のオーバーロード

  関数のオーバーロードは関数の特殊なケースです。C++ では、同じスコープ内で同様の関数を持つ同じ名前の複数の関数を宣言できます。同じ名前を持つこれらの関数の仮パラメータ リスト (パラメータの数またはタイプまたは入力順序) は異なり、異なるデータ型で同様の関数を実装する問題に対処するためによく使用されます。
ここに画像の説明を挿入
  関数名が同じであっても、システムはパラメータの型に応じて最も一致する関数を自動的に照合し、呼び出します。

ただし、形式的なパラメータ リスト (パラメータの数またはタイプまたは入力順序) が異なる場合、これら 3 つの条件のうち 1 つだけが受け入れられます。

では、コンパイラはどのように違いを判断するのでしょうか?

  実際、この関数がエディタ内で呼び出されるときは、関数名とアドレスを追加することで見つけられます。リンク時の各関数の内部関数名は、コンパイラが作成した関数名 (fun) に基づいて、いくつかの記号を追加します。パラメータに従って変更します。たとえば、VS2019 では、リンク処理中の 2 つの関数の関数名は図のようになり、1 つは HN、もう 1 つは NH になります。したがって、コンパイラはそれらを正確に区別します。
ここに画像の説明を挿入
  C言語では内部関数名の修飾は同じなのでコンパイラは区別できません。このことから、同じ名前の関数を区別する方法がないため、C 言語がオーバーロードをサポートできない理由がわかりました。C++ は関数の変更ルールによって区別されており、パラメータが異なれば変更名も異なり、オーバーロードもサポートされます。

2 つの関数の関数名とパラメーターが同じでも、戻り値が異なる場合、コンパイラーには呼び出し時に区別する方法がないため、オーバーロードにはなりません。

6. 引用

  参照は、変数の新しい定義ではなく、既存の変数の別名 (つまり、ニックネーム) です。コンパイラは参照変数用にメモリ空間をオープンせず、参照変数と同じメモリ空間を共有します。を指します。
ここに画像の説明を挿入
  たとえば、ある空間の名前を a として、それに b というニックネームを付けた場合、名前は異なりますが、それは同じ空間です。
ここに画像の説明を挿入
  二つの名前のように見えますが、実は同じ空間で、一方は繁栄し、もう一方はダメージを受けています。あなたは私であり、私はあなたの関係です。認識しなければならないのは参照型は参照されるエンティティと同じ型である必要があります

6.1 リファレンスの特徴

  1. 参照は定義時に初期化する必要があります
  2. 変数には複数の参照を含めることができます
  3. 参照がエンティティを参照すると、別のエンティティを参照できなくなります
int main()
{
    
    
	int a = 10;
	int& b;
	//正确写法:int& b = a;
	return 0;
}

  既存の変数にエイリアスを設定しており、初期化せずに他の人のニックネームとして存在することはできないため、この方法で記述することはできません。

int main()
{
    
    
	int a = 10;
	int& ra = a;
	int& raa = a;
	return 0;
}

  このように書くことも可能で、変数には多くのニックネームを付けることができます。でもニックネームって一人しか使えないから誰でも使えるとめちゃくちゃなことになるじゃないですか参照がエンティティを参照すると、別のエンティティを参照できなくなります
  const で変更された変数は、読み取りのみで書き込みはできないことを意味するため、const 変数のエイリアスを作成する際には、ニックネームの追加による変更ができないように、const も追加する必要があります。

void test()
{
    
    
    const int a = 10;
    int& ra = a;   // 该语句编译时会出错,a为常量
    //正确写法:const int& ra = a;
    
    const int& ra = a;
    int& b = 10; // 该语句编译时会出错,b为常量
    //正确写法:const int& b = 10;
    
    const int& b = 10;
    double d = 12.34;
    int& rd = d; // 该语句编译时会出错,类型不同
    //正确写法:const int& rd = d;
}

  そして、最後の型が異なる場合、なぜ const を追加するのでしょうか? これは、暗黙的な型変換を実行するときに一時的な int が最初に生成されるためです。絶え間ない, まずdの値をdouble型からint型に変換して一時変数に代入し、その一時変数にエイリアスを付けます。定数なので変更できないため、エイリアスをとる場合もconstを付ける必要があります。

6.2 参照される使用シナリオ

  関数の引数として使用すると、ポインターを必要とせずに 2 つの変数の値を交換できます。

void Swap(int& left, int& right)
{
    
    
   int temp = left;
   left = right;
   right = temp;
}

  戻り値として。変数のエイリアスが直接返されるため、参照によって返す方が高速になります。通常の関数では、呼び出し後に関数が破棄されるため、まず戻り値を一時変数に渡し、その一時変数をメイン関数に返します。したがって、次のことに注意してください。参照が返されるときは、静的変数またはヒープ上の変数を返す必要があります。

int& Count()
{
    
    
   static int n = 0;
   n++;
   // ...
   return n;
}

値はパラメーターまたは戻り値の型として使用されます。パラメーターの受け渡しと戻りの際、関数は実際のパラメーターを直接渡したり、変数自体を直接返したりするのではなく、実際のパラメーターを渡したり、変数の一時的なコピーを返したりするため、値はまたは戻り値の型が非常に非効率的です。特にパラメーターまたは戻り値の型が非常に大きい場合、効率はさらに低くなります。

6.3 参照とポインタ

  ポインターと参照は異なる方法で使用されますが、基礎となる実装は実際には同じです。そのようなコードを見てみましょう。

#include<iostream>
using namespace std;
int main()
{
    
    
	int a = 10;
	int* pa = &a;
	int& ra = a;

	++(*pa);
	++ra;
	return 0;
}

  私はアセンブリについてよく理解していませんが、ポインタ演算と参照演算の場合、コンパイラは最下層で同じアセンブリを実装するため、参照が実際にはポインタを介して実装されていることがわかります。
ここに画像の説明を挿入
ここに画像の説明を挿入

  1. 参照は概念的に変数の別名を定義し、ポインターは変数のアドレスを格納します。
  2. 参照は定義時に初期化する必要があり、ポインタは必要ありません
  3. 初期化中に参照がエンティティを参照した後は、他のエンティティを参照することはできず、ポインタはいつでも
    同じタイプのエンティティを指すことができます。
  4. NULL 参照はありませんが、NULL ポインターはあります
  5. sizeof では意味が異なります。参照結果は参照型のサイズですが、ポインタは常にアドレス空間が占有するバイト数です (32 ビット
    プラットフォームでは 4 バイト)。
  6. 参照の自己インクリメントは、参照されるエンティティが 1 ずつ増加することを意味し、ポインターの自己インクリメントは、ポインターが型のサイズを後方にオフセットすることを意味します。
  7. マルチレベル ポインタはありますが、マルチレベル参照はありません
  8. エンティティにアクセスするにはさまざまな方法があり、ポインタは明示的に逆参照する必要があり、リファレンス コンパイラがそれを単独で処理します。
  9. 参照はポインタよりも比較的安全に使用できます。

7. インライン関数

  inline で変更された関数は、インライン関数と呼ばれます。コンパイル時に、C++ コンパイラは、インライン関数が呼び出された場所でその関数を展開します。スタック フレームを構築するための関数呼び出しのオーバーヘッドはありません。インライン関数は、プログラムの効率を向上させます。手術。

inline void Fun(int& a, int& b)
{
    
    
	int tmp = a;
	a = b;
	b = tmp;
}

int main()
{
    
    
	int a = 10, b = 20;
	Fun(a, b);
	return 0;
}
int main()
{
    
    
	int a = 10, b = 20;
	int tmp = a;
	a = b;
	b = tmp;
	return 0;
}

  インライン関数の機能は、上記のコードを次のコードに変換すること、つまり、関数を呼び出すのではなく、関数コードをその場で展開することです。これは C 言語のものと似ていることがわかりましたか? はい、似ています。大きい

#define Add(a,b) ((a) + (b))

  これは、加算関数をマクロで実装するものです。マクロの対応する位置を直接置換することはわかっていますが、演算子には優先順位があることがわかっています。直接置換すると、演算子の優先順位が正しくなくなり、エラーが発生する可能性があります。

マクロの欠点:

  1. マクロのデバッグには不便です。(プリコンパイルフェーズが置き換えられるため)
  2. コードの可読性、保守性が低下し、悪用されやすくなります。
  3. 型安全性のチェックはありません。

マクロの利点

  1. 型の厳密な制御はありません。
  2. 小規模な関数を頻繁に呼び出す場合、パフォーマンスを向上させるためにスタック フレームを作成する必要はありません。

  したがって、この種のエラーを回避するために、C++ はこの問題を解決する inline 関数を inline に追加しました。演算子の正しい使用順序を保証するために、意図的に多くのかっこを記述する必要はありません。

7.1 特徴

  1. inline は、空間と時間を交換する方法です。コンパイラが関数をインライン関数として扱う場合、コンパイル段階で関数呼び出しを関数本体に置き換えます。欠点: オブジェクト ファイルが大きくなる可能性があります。利点: 呼び出しが少なくなります。オーバーヘッドを軽減し、プログラムの動作効率を向上させます。
  2. インラインはコンパイラに対する単なる提案です。コンパイラが異なれば、インライン実装メカニズムも異なる場合があります。一般的な提案は次のとおりです: 関数を小さくする (つまり、関数はそれほど長くなく、正確なステートメントはなく、内部実装に依存します)再帰的で頻繁に呼び出される関数はインライン化すべきではありません。そうしないと、コンパイラーはインライン機能を無視します。「C++prime」第 5 版のインラインに関する提案:インライン化はコンパイラに対する単なるリクエストであり、コンパイラは無視できます。
  3. インラインでは、リンクエラーが発生するため、宣言と定義を分離することはお勧めしません。inline展開なので関数アドレスがなく、リンクが見つかりません。

8. 自動キーワード

  初期の C/C++ における auto の意味は次のとおりです: auto で変更された変数は自動メモリを備えたローカル変数ですが、残念ながら誰もそれを使用していません。その理由を考えてみましょう。
  C++11 では、標準委員会は auto にまったく新しい意味を与えました。auto はもはやストレージ型インジケータではなく、コンパイラに指示する新しい型インジケータであり、auto で宣言された変数は、次から派生したコンパイラによってコンパイルされる必要があります。期間。
ここに画像の説明を挿入
  つまり、auto は変数の型を自動的にプッシュします。これは、後で遭遇する比較的長い一部の変数の型に便利です。

typeid().name() の役割は、変数の型を識別することです。

auto を使用して変数を定義する場合は、初期化する必要があります。コンパイル段階で、コンパイラは初期化式に従って auto の実際の型を推測する必要があります。したがって、auto は「型」宣言ではなく、型が宣言されたときの「プレースホルダー」であり、コンパイラはコンパイル中に auto を変数の実際の型に置き換えます。

8.1 注意事項

  auto を使用してポインター型を宣言する場合、auto を使用する場合と auto* を使用する場合に違いはありませんが、auto を使用して参照型を宣言する場合は、& を追加する必要があります。
ここに画像の説明を挿入
  同じ行で複数の変数を宣言する場合、これらの変数は同じ型である必要があります。そうしないと、コンパイラーはエラーを報告します。これは、コンパイラーは実際には最初の型のみを推定し、その後、推定された型で他の変数を定義するためです。

void test_auto()
{
    
    
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  
    // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}
  1. auto を関数のパラメータとして使用することはできません。
  2. auto を直接使用して配列を宣言することはできません。
  3. C++98 の auto との混同を避けるために、C++11 では型インジケーターとしての auto の使用のみが維持されます。
  4. 実際の auto の最も一般的な利点は、後述する C++11 で提供される新しい for ループやラムダ式と組み合わせて使用​​することです。

9. 範囲ベースの for ループ

  通常、次のように配列を反復処理します。

int main()
{
    
    
	int a[5] = {
    
     0,1,2,3,4 };
	for(int i = 0; i < 5; i++)
	{
    
    
		cout << a[i] << " ";
	}
	return 0;
}

  範囲コレクションの場合、プログラマがループの範囲を指定するのは冗長であり、場合によってはエラーが発生しやすくなります。したがって、範囲ベースの for ループが C++11 で導入されました。for ループの後の括弧は、記号「:」によって 2 つの部分に分割されます。最初の部分は範囲内の反復に使用される変数で、2 番目の部分は反復される範囲を表します。
ここに画像の説明を挿入
  実際の処理は、arr の数値を取り出して e に入れて出力し、引き続き 2 番目の数値を取得します。

9.1 使用条件

  1. for ループ反復の範囲を決定する必要があります。
      配列の場合、それは配列内の最初の要素と最後の要素の範囲です。クラスの場合、begin と end のメソッドが提供される必要があり、begin と end はfor ループ反復の範囲。
void test_for(int arr[])
{
    
    
    for(auto& e : arr)
        cout<< e <<endl;
}

  for の範囲が不定であるため、この方法で記述すると問題があります。
2. 反復オブジェクトは ++ および == の演算を実装する必要があります。これはクラス用です。

10. ポインタ制御 nullptr

  C/C++ プログラミングを適切に実践するには、変数を宣言するときに変数に適切な初期値を与えることが最善です。そうしないと、初期化されていないポインタなどの予期しないエラーが発生する可能性があります。ポインタが正当なポイントを持たない場合、基本的に次のように初期化します。

void test_ptr()
{
    
    
	int* p1 = NULL;
	int* p2 = 0;
	//……	
}

  NULL は実際にはマクロであり、従来の C ヘッダー ファイル (stddef.h) には次のコードがあります。

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

  ご覧のとおり、NULL はリテラル定数 0 として定義することも、型なしポインターの定数 (void*) として定義することもできます。どのような定義を採用しても、null 値のポインタを使用する場合、次のようないくつかの問題が必然的に発生します。

void f(int)
{
    
    
 	cout<<"f(int)"<<endl;
}
void f(int*)
{
    
    
 	cout<<"f(int*)"<<endl;
}
int main()
{
    
    
 	f(0);
 	f(NULL);
 	f((int*)NULL);
 	return 0;
}

ここに画像の説明を挿入

  プログラムの本来の意図は f(NULL) を通じて f(int*) 関数のポインタ版を呼び出すことですが、NULL は 0 として定義されているため、プログラムの本来の意図に反します。
  C++98 では、リテラル定数 0 は整数または型なしポインター (void*) 定数のいずれかになりますが、コンパイラーはデフォルトでそれを整数定数として扱います。ポインター モードで使用するには、強制的に次のようにする必要があります。 (ボイド*)0。
  したがって、C++ ではこの状況は区別され、ポインターを参照するために nullptr が特別に使用されます。

10.1 注意事項

  1. nullptr を使用してポインターの null 値を表す場合、nullptr は C++11 で新しいキーワードとして導入されたため、ヘッダー ファイルをインクルードする必要はありません。
  2. C++11 では、sizeof(nullptr) と sizeof((void*)0) は同じバイト数を占めます。
  3. コードの堅牢性を向上させるために、後でポインターの null 値を表すときに nullptr を使用することをお勧めします。

11. まとめ

  初めて C++ を学習する場合は、覚える箇所が多く、難しくはありませんが細かい内容が多いので、今後の復習のためにメモを整理しておくことをお勧めします。
  この記事の単語数は許容範囲内で、C++ の初心者にとってはまだ少し疲れていますが (ため息)、以前よりははるかに良くなりました (喜び)。何か間違っていることを見つけた場合は、プライベート メッセージまたはコメント エリアで指摘してください (謙虚にアドバイスを求め、上司の助けを求めます)。これからも C++ をもっと深く勉強して、皆さんと一緒に進歩していきたいと思いますので、今回はこれで終わります、また次回お会いしましょう!気分がよければ、「いいね!」をクリックして励ましを示してください。

おすすめ

転載: blog.csdn.net/qq_62321047/article/details/132257687