【CからC++への道】名前空間の解析

序文

これはこのコラム [C から C++ への道] の最初の記事で、主に名前空間関連の内容について説明します。作者のレベルが限られているため、修正や交換歓迎。

名前空間

C/C++ では、後で学習する変数、関数、クラスが多数あり、これらの変数、関数、クラスの名前はすべてグローバル スコープ内に存在するため、多くの競合が発生する可能性があります。名前空間を使用する目的は、名前の競合や名前汚染を避けるために識別子の名前をローカライズすることです。名前空間キーワードの出現は、この種の問題を目的としています。

たとえば:

画像-20220912215544787

実際、ヘッダー ファイルに同じ名前の識別子があるかどうかわからないことがあります。その場合は、競合を避けるために別の名前を考えなければなりません。C 言語コンパイラには解決策がありません。一般的には、ユーザーが自分で個々の名前を変更することをお勧めします。

プロジェクト内で相互に協力しているときに、名前の競合が発生することがあります。複数の人々のコードが送信されてマージされた後、名前の競合を確認してください。いくつありますか? 彼らはどこにいる?では、誰のコードが変更されたのでしょうか? これらはすべて面倒なことであり、このグループの人々は間違いなく「なぜあなたではなく私が変更しなければならないのですか?」と考えるでしょう。喧嘩の敗者が変わることはありますか?したがって、C++ 名前空間は、この問題の解決に非常に優れた役割を果たします。

名前空間は実際にはパッケージ識別子を「ラップ」するための領域に分割されています。同じ名前が存在することはできますが、それらは異なる名前空間にあります。競合することなく使用する名前空間を指定できます。

たとえば、上記のコードは次のように変更できます。

#include <stdio.h>
#include <stdlib.h>

namespace random
{
    
    
    int rand = 0;
}

int main()
{
    
    
    printf("hello bit\n");
    printf("%d\n", rand);
}

名前空間ドメインはここで定義され、random という名前が付けられ、rand 変数はこの名前空間で定義されます。最終的な出力結果はどうなるでしょうか?

結果はライブラリ関数 rand のアドレスを出力しますが、なぜ 0 ではないのでしょうか? ここで、名前空間ランダムは中括弧内のコンテンツを囲むために「壁」を使用していることが理解できます。そのため、探しているランドがコンパイラに指定されていない限り、コンパイラは検索時に直接見つけることができません。名前空間変数内 (コンパイラを「壁にひっくり返す」ようにします)。ここで質問があります: 名前空間ランダムの変数 rand はグローバル変数ですか、それともローカル変数ですか? 少しずつ理解していきましょう。

名前空間の定義

名前空間を定義するには、名前空間キーワード、その後に名前空間の名前、そして名前空間のメンバーである {} のペアを使用する必要があります。

以下にいくつかの定義タイプを示します。

// N是命名空间的名字,一般开发中是用项目名字做命名空间名。
//正常的命名空间定义
namespace N
{
    
    
    // 命名空间中可以定义变量/函数/类型
    int rand = 10;
    int Add(int left, int right)
    {
    
    
    	return left + right;
	}
    
    struct Node
    {
    
    
        struct Node* next;
        int val;
    };
}

ご存知ですか、名前空間にはあらゆる種類のものを詰め込むことができるようですが、「全員が拒否される」ようですが、これらのものを保持するのにそれほど多くのスペースがあるのでしょうか? ちょっと待ってください。少し誤解しているかもしれません。名前空間は実際にアプリケーションのメモリを開くわけではなく、変数、型、関数でもありません。内容をカプセル化するために領域を分割するだけであり、内容自体は変更されません。 具体的には:

名前空間はライフサイクルには影響しませんが、ドメインを制限するだけであり、コンパイラの検索ルールに影響します。コンパイラの検索ルールは何ですか? デフォルトは、ローカル優先および上向き検索です。つまり、最初に最も近いローカル ドメインを検索し、見つからない場合はグローバル ドメインに移動し、下向きではなく上向きに検索します。

したがって、前の例では、名前空間ランダムで定義された rand 変数はグローバル変数です。コンパイラが名前空間の「壁」に遭遇すると、その中に何があるかを見ることができず、その中に何があるかも知りません。 rand 変数を指定しない限り、random::randつまりコンパイラに指定しない限り、ランダムな名前空間で rand 変数を使用したいので、コンパイラは rand を見つけるために「壁をひっくり返す」ことになります。::また何ですか?心配しないでください。名前空間の使用については以下で説明します。

名前空間の使用

次のコードを例として、名前空間の 3 つの使用法について説明します。

namespace N
{
    
    
    // 命名空间中可以定义变量/函数/类型
    int a = 10;
    int Add(int left, int right)
    {
    
    
    	return left + right;
	}
    
    struct Node
    {
    
    
        struct Node* next;
        int val;
    };
}

名前空間名とスコープ修飾子を使用して指定します

ドメイン スコープ修飾子を使用して、::どの名前空間のどのメンバーを指定するかを指定します。::その前に名前空間名が続き、その後に指定するメンバーの名前が続きます。指定すると、コンパイラは、デフォルトの規則に従って検索するのではなく、対応する名前空間を直接検索します。つまり、名前空間によってコンパイラの検索規則が変更されます。

int main()
{
    
    
    int x = 5;
    struct N::Node node;//注意结构体的指定用法
    N::a = N::Add(N::a, x);
    printf("%d\n", N::a);
	return 0;
}

Nを指定しなかったら::どうなるでしょうか?

指定しない場合、コンパイラはデフォルトのルールに従って検索し、指定されたフィールドで見つからない場合はエラーを報告します。

using namespace を使用して、名前空間全体を導入します。

std は、公式の C++ ライブラリ コンテンツによって定義された名前空間です。変数や関数を大量に使用する場合など、名前空間内のコンテンツを使用するたびに名前空間を指定するのは少し面倒に感じるかもしれません。using namespace N名前空間を拡張するために使用すると、「壁を取り除き」、コンテンツを直接グローバル ドメインに公開することに相当します。便利に使用できますが、名前空間の意味が失われませんか?

なぜ名前空間を使用するのでしょうか? これは、独自の名前付けと既存のコンテンツの間で名前の競合を防ぐためであり、要件に従ってコンテンツを各名前空間に配置することで、名前の競合を効果的に回避できます。それで、なぜ今それを展開するのですか?実際、この小さな便利さを貪欲にして、より重要なセキュリティを無視してはいけません。日常的な習慣であれば問題ありませんが、プロジェクトの場合は直接開始すべきではありません。

たとえば、名前空間 N を展開すると、N のコンテンツを直接使用できるようになります。

using namespace N;
int main()
{
    
    
    int x = 5;
    struct Node node;
    a = Add(a, x);
    printf("%d\n", a);
	return 0;
}

using を使用して名前空間にメンバーを導入します

妥協は常に狡猾であり、問​​題をより良く解決するために各ソリューションの利点を考慮に入れます。名前空間を拡張することは適切ではありませんが、より使いやすくしたいので、using を使用して必要なメンバーの一部のみをグローバル ドメインに導入し、残りは名前空間に残すことができます。

例えば、Add関数だけを導入した場合は、指定せずにそのまま利用することも可能です。

using N::Add;
int main()
{
    
    
    int x = 5;
    struct N::Node node;//注意结构体的指定用法
    N::a = Add(N::a, x);
    printf("%d\n", N::a);
	return 0;
}

名前空間のネストと構成

名前空間のネスト

//命名空间可以嵌套
namespace N1
{
    
    
    int a;
    int b;
    int Add(int left, int right)
    {
    
    
    	return left + right;
    }
    namespace N2
    {
    
    
        int c;
        int d;
        int Sub(int left, int right)
        {
    
    
            return left - right;
        }
    }
}

a にアクセスする必要がありN1::a、 b にアクセスする必要があるN1::N2::b名前空間の入れ子は「壁」の入れ子とみなすことができ、コンパイラは「N1の壁を覆す」

最後に、内側に別の「N2 壁」があることがわかります。b を見つけるには裏返す必要があります。

名前空間の合成

同じプロジェクト内の複数のファイルで同じ名前を持つ複数の名前空間が許可され、それらは最終的に同じ名前空間に合成され、名前空間のすべてのコンテンツが同じファイルに積み重なることによって引き起こされる肥大化を効果的に回避します。

たとえば、2 つのヘッダー ファイルのネームスペースに異なる構造タイプの定義を配置し、そのヘッダー ファイルをソース ファイルにインクルードした後、ネームスペースのコンテンツを使用します。

画像-20220916104340386


ご覧いただきありがとうございます、あなたのサポートが私の最大の励みです〜

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_61561736/article/details/126897827