C ++入門
1.ネームスペース
c / c ++には、後で学習する変数、関数、クラスが多数あります。これらの変数、関数、クラスの名前はすべてグローバルスコープに存在するため、多くの競合が発生する可能性があります。名前空間を使用する目的名前の競合や名前の汚染を回避するためにローカライズされた名前識別子のShiには、この問題のnamespaceキーワードがあります。
1.1名前空間の定義
名前名を定義するには、namespaceキーワードを使用し、その後に名前名の名前を続ける必要があります。その後、{}のペアで十分です。{}は名前名のメンバーです。
//1.普通的命名空间 namespace N1//N1为命名空间的名称 { //命名空间中的内容,既可以是变量,也可以是定义函数 int a; int Add(int left, int right) { return left + right; } } //2.命名空间可以嵌套 namespace N2 { int a; int b; int Add(int left, int rght) { return left + right; } namespace N3 { int c; int d; int Sub(int left, int right) { return left - right; } } } //3.同一个工程中允许存在多个相同名称的命名空间 //编译器最后会合成同一个命名空间中 namespace N1 { int Mul(int left, int right) { return left * right; } }
[注]:ネームスペースは新しいスコープを定義し、ネームスペース内のすべてのコンテンツはそのネームスペースに制限されます
1.2名前空間での使用
名前名のメンバーはどのように使用する必要がありますか?といった:
namespace N { int a = 10; int b = 20; int Add(int left, int right) { return left + right; } int Sub(int left, int right) { return left - right; } } int main() { cout << a << endl;//该语句编译出错,无法识别a return 0; }
名前付けを使用するには、次の3つの方法があります。
名前名とスコープ修飾子を追加します
using N::b; int main() { printf("%d\n", N::a); return 0; }
名前名にメンバーを紹介するためにusingを使用する
using N::b; int main() { cout << N::a << endl; cout << b << endl; return 0; }
名前名参照を使用する
using namespace N; int main() { cout << N::a << endl; cout << b << endl; Add(10, 20); return 0; }
2. C ++入力&&出力
#include <iostream> using namespace std; int main() { cout << "hello world" << endl; return 0; }
説明:
cout標準出力(コンソール)とcin標準入力(キーボード)を使用する場合は、<iostream>ヘッダーファイルとstd標準名前名を含める必要があります。
c ++を使用して出力と出力を行う方が便利であり、次のようなデータ形式の制御を増やす必要はありません。シェーピング-%d、文字-%c
#include <iostream> using namespace std; int main() { int a; double b; char c; cin >> a; cin >> b >> c; cout << a << endl; cout << b << " " << endl; return 0; }
3.デフォルトパラメータ
3.1デフォルトパラメータの概念
デフォルトパラメータは、関数を宣言または定義するときに関数パラメータのデフォルト値を指定することです。この関数を呼び出すときに、実際のパラメーターが指定されていない場合はデフォルト値が使用され、指定されていない場合は指定された実際のパラメーターが使用されます。
void TestFunc(int a = 3) { cout << a << endl; } int main() { TestFunc();//没有传参时,使用参数的默认值 TestFunc(5);//传参时,使用指定的实参 }
3.2デフォルトパラメータの分類
すべてのデフォルトパラメータ
void TestFunc(int a = 1, int b = 2, int c = 3) { cout << "全缺省参数" << endl; }
半デフォルトパラメータ
void TestFunc(int a, int b = 2, int c = 3) { cout << "半缺省参数" << endl; }
【注意】:
セミデフォルトパラメータは、右から左の順に指定する必要があり、分離することはできません。
デフォルトのパラメータは、関数の宣言および定義と同時に表示することはできません
//test.h void TestFunc(int a = 1, int b =2) { } //test.cpp void TestFunc(int a = 2, int b = 1) { } //注意:如果声明和定义位置同时出现,恰巧两个位置提供的值不同,那么编译器就无法确定到底要用那个缺省值
デフォルト値はグローバル変数である必要があります
C言語はデフォルトをサポートしていません(コンパイラはサポートしていません)
4.機能の過負荷
4.1関数のオーバーロードの概念
関数のオーバーロード:これは関数の特殊なケースです。C++では、同じスコープで同様の関数を持つ同じ名前の複数の関数を宣言できます。同じ名前のこれらの関数のパラメーターリスト(パラメーターの数、タイプ、または順序)は異なっている必要があります。同様の機能と異なるデータタイプの問題に対処します。
int Add(int left, int right) { return left + right; } double Add(double left, double right) { return left + right; } float Add(float left, double right) { return left + right; }
[注]:パラメータの順序もオーバーロードされる可能性があります
#include <iostream> using namespace std; class Test { public: void TestFunc(int a, float b) { cout << "int next float" << endl; } void TestFunc(float a, int b) { cout << "float next int" << endl; } private: int _a; }; int main() { Test a; a.TestFunc(2, 2.1); a.TestFunc(2.1, 2); return 0; }
出力結果:int next float float next int
結論:について関数のオーバーロード、だけの数の関数のパラメータ、異なるパラメータの型、およびパラメータの順序が過負荷状態にするために使用することができます。には十分ではないだけ異なる戻り値を持っています。
[インタビューの質問]:関数の場合、戻り値のみが異なりますが、これら2つの関数をオーバーロードできますか?
回答:いいえ、それは関数の名前の変更によって決定されます。
最下層のC ++コンパイラの場合、関数の名前ではなく、再変更されたより複雑な名前です。再変更された名前には、関数の名前とパラメータタイプが含まれているため、関数がオーバーロードされます。同じ名前の複数の関数が異なるパラメーターリストを必要とする理由。パラメータリストが異なる限り、コンパイラはコンパイル時に関数名を再変更し、最終名にパラメータタイプを含めて、下部の一意性を確保できます。
したがって、関数をオーバーロードできるかどうかは、戻り値ではなく、主にパラメータリストに関連しています。戻り値はコード実行フェーズでのみチェックされ、パラメーターは関数名のコンパイル中に変更されます。
4.2名前の変更
c / c ++では、プログラムを実行するには、前処理、コンパイル、アセンブリ、リンクの各段階を経る必要があります。
名前マングリングは、コンパイルプロセス中に関数と変数の名前を再配置するメカニズムです。簡単に言えば、各関数を区別するために、コンパイラは特定のアルゴリズムを聞いた後、関数をグローバルに一意の名前に再変更します。
C言語の名前変更ルールは非常に単純で、関数名の前に下線を追加するだけです。たとえば、次のコードの場合、リンクの最後でエラーが発生します。
int Add(int left, int right); int main() { cout << Add(3, 4) << endl; return 0; }
コンパイラはエラーを報告しました:エラーLNK2019:関数_mainで参照されている未解決の外部シンボル_Add。
C ++は関数のオーバーロード、名前付けなどをサポートする必要があるため、変更ルールがより複雑になるため、コンパイラが異なれば、下部に実装も異なる可能性があります。
下部のC ++コンパイラの場合、これは関数の名前ではなく、再変更されたより複雑な名前です。再変更された名前には、関数の名前とパラメータタイプが含まれているため、関数がオーバーロードされます。同じ名前のいくつかの関数には、異なるパラメーターリストが必要です。パラメータリストが異なる限り、コンパイラはコンパイル時に関数名を再変更し、最終名にパラメータタイプを含めて、下部の一意性を確保できます。
[Linuxでの関数名の変更規則]:
C ++の場合、関数名は関数の名前とパラメーターを考慮します
cの場合、関数の名前のみが考慮されます(c言語は関数のオーバーロードをサポートしていないため、変更ルールは単純です)
//.cpp int Add(int leftm int right) { } //修饰:Add(int , int) //只有函数名字和参数 //.c int Add(int left, int right) { } //修饰:Add //只有函数名字
[C ++関数名の変更規則]:
関数の名前、パラメータータイプと戻り値、および名前名はすべて、変更された名前に追加されます。
5.外部「C」
C ++プロジェクトでは、特定の関数をCのスタイルでコンパイルする必要がある場合があります。関数の前にextern "C"を追加します。これは、C言語の規則に従って関数をコンパイルするようにコンパイラーに指示することを意味します。
extern "C" int Add(int left, int right); int main() { Add(2, 3); return 0; }
リンク時にエラーが報告されます:エラーLNK2019:未解決の外部シンボル_Add、** function_mainで参照されています
[面接の質問]:
次の2つの機能をオーバーロードできますか?問題はありますか?または、どのような状況でうまくいかないのでしょうか?
#include <iostream> using namespace std; class Test { public: void TestFunc(int a = 9) { cout << "haveParameter:" << a << endl; } void TestFunc(int a) { cout << "noHaveParameter" << a << endl; } private: int _a; }; int main() { Test t; t.TestFunc(10); return 0; }
回答:これら2つの機能はオーバーロードできません。
デフォルト以外の関数、関数パラメーターは再宣言できません
C言語がオーバーロードをサポートしないのはなぜですか?
回答:これは、コンパイル時に関数名の変更規則が異なるためです。
c言語の関数名が変更された場合、同じ変更された関数名からの関数名が同じであり、パラメーターのタイプ、パラメーターの数、関数スペースの名前、およびより複雑なC ++の関数名マングリング規則に依存しない限り、規則は単純です。関数名の変更は、関数名だけでなく、関数パラメーターの数、パラメータータイプ、パラメーターの順序、および名前空間にも関連しています。
したがって、C言語はオーバーロードをサポートしていません。
関数のオーバーロードの最下層はC ++でどのように処理されますか?
回答:基になる名前変更メカニズムは、パラメーターの数、パラメータータイプ、および戻り値タイプに応じてAdd関数の名前を変更します。次に、関数のオーバーロードにより、関数には複数の命名メカニズムがあります。
C ++呼び出し規則(_cdecl呼び出し規則)では、Add関数は次のように解析されます。
"int __cdecl Add(int、int)"(?Add @@ YAHHH @ Z) "double __cdecl Add(double、double)"(?Add @@ YANNN @ Z)
関数は、C言語スタイルに従ってC ++スタイルでコンパイルできますか?
回答:C ++は、関数宣言の前に[extern "C"]を追加して、関数をC言語スタイルに従ってコンパイルすることができます。
6.引用
6.1参照の概念
参照は変数の新しい定義ではありませんが、既存の変数のエイリアスです。コンパイラは参照変数のメモリスペースを開きません。参照する変数と同じメモリスペースを共有します。
タイプと参照名(オブジェクト名)=参照エンティティ;
例:
void Test { int a = 10; int& ra = a; //定义引用类型 printf("%p\n", &a); printf("%p\n", &ra); }
[注]:参照タイプは、参照エンティティと同じタイプである必要があります
6.2参照特性
定義時に参照を初期化する必要があります
変数は複数の参照を持つことができます
エンティティを参照すると、他のエンティティを参照できなくなります
6.3頻繁に引用される
//常引用 #include <iostream> using namespace std; class Test { public: void TestFunc() { const int a = 10; //int& ra = a;//编译出错a为常量 const int& ra = a;//引用类型要匹配 //int& b = 10; //编译出错b为常量 } }; int main() { Test t; t.TestFunc(); return 0; }
6.4使用シナリオ
パラメータを作成する
戻り値を実行します
次のコードの出力は何ですか?どうして?
//引用返回的局部变量 #include <iostream> using namespace std; class Test { public: int& Add(int left, int right) { int c = left + right; return c; } }; int main() { Test t; cout << t.Add(2, 3) << endl; return 0; }
【注意】:関数が戻って離れる場合、スタック上のスペースは関数スコープを離れた後にシステムに戻されているため、スタック上のスペースを参照タイプとして返すことはできません。参照タイプとして返される場合、戻り値の期間は関数によって制限されてはなりません(つまり、関数の有効期間より長くなります)。
6.5値渡しと参照渡しの効率の比較
パラメータまたは戻り値型として使用する値。パラメータ転送と復帰時には、関数が直接実パラメータを渡すまたは変数自体を返さないが、実際のパラメータを渡すまたは変数の一時的なコピーを返す値がパラメータとして使用されるように、または戻り値のタイプは非常に非効率的です。特に、パラメーターまたは戻り値のタイプが非常に大きい場合、効率はさらに低くなります。
ポインタと参照をパラメータまたは戻り値のタイプとして使用する場合、効率はほぼ同じです。
6.6参照とポインタの違い
面では文法、参照がある別名、独立したスペースがない、そしてそれは、その参照エンティティと同じスペースを共有します
で基本となる実装、実際に参照がスペースがありますので、参照はポインタを使用して実装されている中で
【リファレンスとポインタアセンブリコードの比較】
[参照とポインタの比較]:
参照定義を初期化する必要があり、ポインタは必要ありません
参照は、エンティティを参照した後に別のエンティティを参照することはできません。また、ポインタは、いつでも同じタイプの任意のエンティティを指すことができます。
NULL参照はありませんが、NULLポインター
sizeofの意味が異なり、参照の結果は参照タイプのサイズになりますが、ポインターは常にアドレス空間が占めるバイト数のサイズになります(32ビットマシンでは4バイト)。
参照に1を追加すると、参照されるエンティティに1が追加され、ポインタに1を追加すると、型のサイズが後方にオフセットされます。
マルチレベルのポインタがあり、マルチレベルの参照はありません
エンティティにアクセスする方法は異なり、ポインタは明示的に逆参照される必要があり、参照コンパイラはそれ自体を処理します
参照はポインタよりも安全に使用できます
7.範囲ベースのforループ(C ++ 11)
7.1範囲forループの構文
C ++ 11で配列をループする場合は、配列の範囲を指定する必要はありません。範囲ベースのforループを使用するだけで済みます。
forループの後の括弧内の内容は、コロンによって2つの部分に分割されます。最初の部分は反復に使用される変数であり、2番目の部分は反復の範囲を示します。
例:
#include <iostream> int main() { int array[10]; int i = 1; for (auto& e : array) { e = i++; } for (auto e : array) { std::cout << e << '\n'; } return 0; }
for rangeループの場合、原則はイテレーター、begin、endを使用することです。
【注意】:
for rangeループは通常のループに似ています。continueを使用してこのループを終了するか、breakを使用してループ全体からジャンプできます。
7.2範囲の使用条件
forループ反復の範囲は固定する必要があります
配列の場合、反復範囲は最初の要素と最後の要素の間の範囲です。クラスの場合、イテレーターメソッドの開始と終了を提供する必要があります。beginとendは、ループの繰り返しの範囲です。
反復オブジェクトは、++および==の操作を実装する必要があります
8.自動の使用
C / C ++の初期には、autoを使用して変数を変更していました。変数の前に追加すると、その変数が自動変数であることを示します。(実際、これはローカル変数です)
自動変数:
実行フローが関数に入ると、変数のストレージスペースが自動的に割り当てられ、実行が関数から流出すると、変数のストレージスペースが自動的に解放されます。
ただし、C ++ 11では、キーワードが変更されました。Autoはストレージタイプインジケータではなくなりましたが、新しいタイププロンプトになりました。autoによって宣言された変数は、コンパイル時にコンパイラによって推定される必要があります。タイプ。
【注意】:
autoを使用して定義された変数は初期化する必要があります。そうしないと、変数のタイプが不明になり、コンパイル中にエラーが発生します。コンパイル中に、コンパイラは式の初期化に基づいてautoの実際のタイプを初期化する必要があります。
autoの場合、これは「型宣言」ではなく、型宣言の「プレースホルダー」です。コンパイラーは、コンパイル中にautoを変数の実際の型に置き換えます。
8.1自動およびポインタと参照
以下のためにポインタと自動連動が可能*追加しない、また可能*追加されます。
ただし、autoを参照して使用する場合は&を追加する必要があります。
8.2自動の無効化
関数の実際のパラメーターを受け取るための関数パラメーターとしてautoを使用することはできません
autoが正式なパラメーターとして使用されている場合、実際のパラメーターは配列の配列であり、要件を満たしていないため、エラーが発生します。
autoを使用して同じ行に複数の変数を定義する場合、変数タイプは同じである必要があります
複数を同時に定義する場合は、最初の変数の型を使用してautoを置き換えるだけなので、後続の変数の型が最初の変数の型と一致しない場合、エラーが発生します。
autoを直接使用して配列を宣言することはできません
autoC ++ 11の場合、タイプインジケーターとしてのautoの使用のみが予約されています。
テンプレートをインスタンス化するときに、autoをテンプレートパラメータとして使用することはできません。
9.nullptr与nullptr_t
Nullptrはnullポインター定数を表し、 nullptrのタイプはnullptr_tです。
typedef decltype(nullptr) nullptr_t;
【注意】:
nullptrを使用してポインタのnull値を示す場合、nullptrはC ++ 11のキーワードに従って導入されるため、ヘッダーファイルを含める必要はありません。
C ++ 11では、sizeof(nullptr)とsizeof((void *)0)は同じバイト数を占めます
コードの堅牢性を向上させるために、後続のコードでポインタがnullの場合はnullptrを使用するのが最適です。