C++ - namespace

Table of contents

1. C language naming conflict

2. Namespace definition

3. Namespace usage

  • Maybe when you look at the C++ code written by others, you will include this header file at the beginning: #include<iostream>

This header file is equivalent to the #include<stdio.h> we learned in C language. It is used for input and output to our console. It is briefly mentioned here and discussed in detail later.

  • In addition to the above header file, there is also this line of code: using namespace std;

namespace is the first keyword we want to use in C++, it is namespace.

In C/C++, there are a large number of variables, functions, and classes to be learned later. The names of these variables, functions, and classes will all exist in the global scope, which may cause many conflicts. The purpose of using namespaces is to localize identifier names to avoid naming conflicts or name pollution . The namespace keyword appears to address this problem.

1. C language naming conflict

 Before officially introducing namespace, let’s review the naming conflict problem in C language:

#include<stdio.h>
//命名冲突
int rand = 0;
int main()
{
	printf("%d", rand);
	return 0;
}

In the above code, we only use intclude<stdio.h> for the header file and nothing else. We defined the global variable rand and the code compiles normally without any errors.

But you must know that there is a library function in C language that is rand, but you need to include the header file #include<stdlib.h>, include this header file, and try running again:

There is obviously a naming conflict here. The global variable rand we defined conflicts with the rand function in the library.

It is very simple to solve this problem. Some people may say that I can just change the variable name. It is indeed possible, but it is not a long-term solution. If I use the variable more than 100 times without knowing it, do you want a A modification? This fully reflects the naming conflict of C language.

In C++, the introduced namespace solves the naming conflict problem of C language very well.

2. Namespace definition

To define a namespace, you need to use the namespace keyword, followed by the name of the namespace, and then followed by a pair of { }. The members in {} are the members of the namespace.

as follows:

 Two identical variables cannot appear in the same scope . At this time, rand is locked in the namespace domain of n1 and is isolated from other things. Therefore, no naming conflict will occur when the stdlib.h header file is expanded. At this time, the printing of rand is the address of rand in the library function. rand is a function pointer, and the address is printed.

Another example:

This code more fully reflects that adding a namespace can not only avoid naming conflicts, but also tells us that when accessing variables m, c, and f at this time, they are all accessed in the global domain, and the xzy namespace domain The variables inside and the global domain establish a wall and do not interfere with each other. However, c and m are still global variables here , and the namespace does not affect the life cycle .

Namespaces have three major characteristics:

  • 1. Namespace can define variables, functions, and types
//1. 普通的命名空间
namespace N1 // N1为命名空间的名称
{
	// 命名空间中的内容,既可以定义变量,也可以定义函数,也可以定义类型
	int a; //变量
	int Add(int left, int right) //函数
	{
		return left + right;
	}
    struct ListNode //类型
    {
        int val;
        struct ListNode* next;
    }
 
}
  • 2. Namespaces can be nested
//2. 命名空间可以嵌套
namespace N2
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N3
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}
  • 3. Multiple namespaces with the same name are allowed to exist in the same project. The compiler will eventually synthesize them into the same namespace.
//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
namespace N1
{
	int Mul(int left, int right)
	{
		return left * right;
	}
}

3. Namespace usage

We all know that in C language, there are local precedence rules, as follows:

int a = 0; //全局域
int main()
{
	int a = 1; //局部域
	printf("%d\n", a); // 1 局部优先
	return 0;
}

We all know that the result here is 1, but what if I have to print a in the global domain?

This introduces the domain scope qualifier ::  ), and the effect is as follows:

With the addition of (  :  :), the a being accessed at this time is the global domain. The reason why it is the global domain is that the front of "  :: " is blank. If it is blank, then the global domain is accessed. If you look at it this way, I If you replace the namespace domain in front of :: ", you can access the content in the namespace domain. In fact, "  :: " is a way of using namespace.

 For example, we define the following namespace:

namespace n1 
{
	int f = 0;
	int rand = 0;
}

Now how do we access the contents of the namespace domain? Actually there are 3 ways:

  1. Add the namespace name and scope qualifier "  :: ";
  2. Use using namespace to expand all namespace names;
  3. Use using to expand the members in the namespace.
  • 1. Add the namespace and scope qualifier "::"
int main()
{
	printf("%d\n", n1::f); //0
	printf("%d\n", n1::rand);//0
	return 0;
}

In order to prevent the same variable or type from being defined, we can define multiple namespaces to avoid it.

namespace ret
{
	struct ListNode
	{
		int val;
		struct ListNode* next;
	};
}
 
namespace tmp
{
	struct ListNode
	{
		int val;
		struct ListNode* next;
	};
	struct QueueNode
	{
		int val;
		struct QueueNode* next;
	};
}

When we want to use them, it's as follows:

int main()
{
	struct ret::ListNode* n1 = NULL;
	struct tmp::ListNode* n2 = NULL;
	return 0;
}

For namespace nesting, as follows:

 It can be accessed like this:

int main()
{
	struct tx::List::Node* n1; //访问List.h文件中的Node
	struct tx::Queue::Node* n2;//访问Queue.h文件中的Node
}

But the above access method is a bit too cumbersome . Can you omit some repetitions? For example, instead of writing tx::, here comes the second method of namespace access:

  • 2. Use using namespace to expand all namespace names.
using namespace tx;

This sentence means to release the things defined in the tx namespace, so we can access it like this:

int main()
{
	struct List::Node* n1; //访问List.h文件中的Node
	struct Queue::Node* n2;//访问Queue.h文件中的Node
}

Of course, I can also remove another layer, as follows:

using namespace tx;
using namespace List;
int main()
{
	struct Node* n1; //访问List.h文件中的Node
	struct Queue::Node* n2;//访问Queue.h文件中的Node
}

When expanding, please note that the order of tx and List cannot be reversed.

This access method can achieve a simplified effect, but there is also a certain risk: all the namespaces are released and naming conflicts return .

 Therefore, specific naming conflict issues need to be discussed separately:

From this we learn that it is not good to expand everything. We need to ask for it on demand and expand what we use, which leads to the third method of use.

  • 3. Use using to expand the members in the namespace.

For the above code, we only put f:

namespace n1
{
	int f = 0;
	int rand = 0;
}
using n1::f;
int main()
{
	f += 2;
	printf("%d\n", f);
	n1::rand += 2;
	printf("%d\n", n1::rand);
}
  • Let’s take a look at the C++ standard library namespace:
#include<iostream>
using namespace std; //std 是封C++库的命名空间
int main()
{
	cout << "hello world" << endl; // hello world
	return 0;
}

If you omit this line of code: using namespace std;

If you want to output hello world, do this:

#include<iostream>
int main()
{
	std::cout << "hello world" << std::endl;
	return 0;
}

Of course it can also be like this:

#include<iostream>
using std::cout;
int main()
{
	cout << "hello world" << std::endl;
	return 0;
}

This makes full use of namespaces.

 

Guess you like

Origin blog.csdn.net/m0_49687898/article/details/131350690