C ++ || C ++の紹介

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;
}

説明:

  1. cout標準出力(コンソール)とcin標準入力(キーボード)を使用する場合は、<iostream>ヘッダーファイルとstd標準名前名を含める必要があります。

  2. 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;
}

【注意】:

  1. セミデフォルトパラメータは、右から左の順に指定する必要があり、分離することはできません。

  2. デフォルトのパラメータは、関数の宣言および定義と同時に表示することはできません

//test.h
void TestFunc(int a = 1, int b =2)
{
    
}
​
//test.cpp
void TestFunc(int a = 2, int b = 1)
{
    
}
​
//注意:如果声明和定义位置同时出现,恰巧两个位置提供的值不同,那么编译器就无法确定到底要用那个缺省值
  1. デフォルト値はグローバル変数である必要があります

  2. 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で参照されています

[面接の質問]:

  1. 次の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つの機能はオーバーロードできません。

デフォルト以外の関数、関数パラメーターは再宣言できません

  1. C言語がオーバーロードをサポートしないのはなぜですか?

回答:これは、コンパイル時に関数名の変更規則が異なるためです。

c言語の関数名が変更された場合、同じ変更された関数名からの関数名が同じであり、パラメーターのタイプ、パラメーターの数、関数スペースの名前、およびより複雑なC ++の関数名マングリング規則に依存しない限り、規則は単純です。関数名の変更は、関数名だけでなく、関数パラメーターの数、パラメータータイプ、パラメーターの順序、および名前空間にも関連しています

したがって、C言語はオーバーロードをサポートしていません。

  1. 関数のオーバーロードの最下層はC ++でどのように処理されますか?

回答:基になる名前変更メカニズムは、パラメーターの数、パラメータータイプ、および戻り値タイプに応じてAdd関数の名前を変更します。次に、関数のオーバーロードにより、関数には複数の命名メカニズムがあります。 

C ++呼び出し規則(_cdecl呼び出し規則)では、Add関数は次のように解析されます。

"int __cdecl Add(int、int)"(?Add @@ YAHHH @ Z) "double __cdecl Add(double、double)"(?Add @@ YANNN @ Z)

  1. 関数は、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参照特性

  1. 定義時に参照を初期化する必要があります

  2. 変数は複数の参照を持つことができます

  3. エンティティを参照すると、他のエンティティを参照できなくなります

 

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参照とポインタの違い

  • 面では文法、参照がある別名独立したスペースがないそしてそれは、その参照エンティティと同じスペースを共有します

  • 基本となる実装、実際に参照がスペースがありますので、参照はポインタを使用して実装されている中で

  • 【リファレンスとポインタアセンブリコードの比較】

 

[参照とポインタの比較]

  1. 参照定義を初期化する必要があり、ポインタは必要ありません

  2. 参照は、エンティティを参照した後に別のエンティティを参照することはできません。また、ポインタは、いつでも同じタイプの任意のエンティティを指すことができます。

  3. NULL参照ありませんが、NULLポインター

  4. sizeof意味が異なり、参照の結果は参照タイプのサイズになりますが、ポインターは常にアドレス空間が占めるバイト数のサイズになります(32ビットマシンでは4バイト)。

  5. 参照に1を追加すると、参照されるエンティティに1追加され、ポインタに1追加すると、型のサイズが後方にオフセットされます。

  6. マルチレベルのポインタがあり、マルチレベルの参照はありません

  7. エンティティにアクセスする方法は異なりポインタ明示的に逆参照される必要があり、参照コンパイラはそれ自体を処理します

  8. 参照はポインタよりも安全に使用できます

 

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を使用するのが最適です。

 

おすすめ

転載: blog.csdn.net/qq_40399012/article/details/84138724