334 - C++ Nested
🧑💻 User
In this lecture, we’re going to learn about nested namespaces.And this is a facility we have in the C plus plus programming language to be able to set up namespacesinside other namespaces.For example, here we have the hello namespace, and inside that namespace we have another namespacecalled World.And one thing you should know is that inner namespaces have direct access to things declared in theouter namespace.For example, the world namespace here is going to have direct access to the age name here.It’s not going to have to go through some namespace name to access that and we can see that here.But outer namespaces have to go through the namespace name to access things.We declare an inner namespaces and if you look at this, do something function here.If it wants to access this local variable here, it’s going to go through the world namespace name becausethat’s where this thing is declared.Once you know this, you’re going to head over to the main function or wherever in your code and you’regoing to use your namespaces however you want.One thing you should know is that to get to the inner namespace, you have to go through the namespaces.For example, we say hello, we say Colon, we say world, we say colon.Then we’re going to access something inside our nested namespace here.Now that you know this, we’re going to head over to Visual Studio code and play with this a littlemore.Okay, Here we are in our working folder.The current project is nested namespaces.We’re going to grab our template files pretty quick and we’re going to put them in place and we aregoing to open this in Visual Studio code pretty quick.We’re going to have our main CPP file here.Let’s clean up a little bit.We’re going to remove what we don’t need here.We can close the left sidebar and I am just going to put in the code we’re going to play with becauseI don’t want you to waste your time typing all this things.We have an outer namespace called Hello.It is delimited by the curly braces on line three and line 20 as you see here.And inside that we have another namespace delimited by the curly braces.We have on line six and 13.As you see here, the inner namespace is called World.The outer namespace is called Hello.And we have things inside all these namespaces.The outer namespace, which is Hello, has a variable called age.We have a value inside in the inner namespace.We have a local variable which has a 44 inside and we have a function called say something inside thefunction we are saying just hello there and we are trying to access the variable that was declared inthe outer namespace and we can access that directly without going through the namespace name.That’s what I want you to see here in the outer namespace.We also have another function which is do something here and this function doesn’t have direct accessto the variables we have in our local namespace here or inner namespace to access the local var here,it will have to go through the world namespace and that’s what you see here.If you take out the world here, you’re going to see that we’re going to get a compiler error.Okay, Now that we have this in place, we can try and use this tense in the main function.For example, we can try and call the say something function here.But before we do that, please try and see if you can do this on your own.Please call this function world and run the program and see that you see the output here.Okay.If you have done this, congratulations.But if you had any problem, please watch what I’m going to do here.We’re just going to say hello and we’re going to put colon.Colon.We’re going to say world to access the inner namespace.We’re going to put colon.Colon, and then we’re going to call our function here.Say something.This is the syntax you use to use nested namespaces, and this is really cool.We’re going to build the application using GCC.The world is going to be good.We’re going to bring up a terminal to try things out.We’re going to clear and run Rooster.You’re going to see that we say hello there, which is the message here.And we’re going to say the age is H and we’re going to be accessing a variable that lives in the outerHello namespace here.And this is really cool.If you want, you can also call a function living in our outer namespace.That function happens to be this do something function here.So all we have to do is say hello and say do something.Okay, this is going to do our thing.We’re going to build this.The world is going to be good.As you see here, we’re going to clear and run Rooster.We’re going to say using local Var, and that’s going to be 44 here.Please notice that we are going through the world namespace to access the local variable here.If you take out this world namespace, you’re going to get a compiler error because now local Var isnot going to be accessible or defined in this scope here.That’s the error you’re going to get.Let’s try and build this because I want you to know that I am not making this up.This is what we’re going to see.We’re going to see local.Var was not declared in this scope and that’s going to be a compiler error.To be able to use this, we have to specify the namespace where it is living and if we do this now,this is going to be fine because now the compiler is going to go through this namespace and access thislocal variable here and we’re going to print it out and see it on our console.Let’s bring this up a little bit.You see the world is good.We can clear and run Rooster and we’re going to see that our local variable is 44.This is really all I wanted you to see in this lecture that you can set up nested namespaces if thisis helpful for whatever project you are doing in C plus plus, please use this facility and it is goingto make your life easier.Just remember to go through the syntax like this to access things that lives inside nested namespaces.We are going to stop here in this lecture and the next one we’re going to learn about namespaces, aliases.Go ahead and finish up here and meet me there.
🤖 Assistant
好的,欢迎来到C++的学习之旅!作为您C++旅程的导师,我将尽我所能,用最清晰、最易懂的方式,带您深入理解C++中的重要概念。
深入理解C++嵌套命名空间:组织代码的强大工具
摘要: 本节课将详细讲解C++中如何使用[嵌套命名空间] (nested namespaces) 来更好地组织您的代码,区分同名实体,并探讨内层和外层命名空间成员之间的访问规则。我们将通过详细的示例代码来理解其工作原理,并识别常见的使用误区。
1. 什么是命名空间 (Namespace)?
在深入了解嵌套命名空间之前,我们首先要理解什么是[命名空间] (namespace)。
想象一下,你和你的朋友们都在各自的家里养宠物。你可能养了一只狗叫”旺财”,你的朋友可能也养了一只狗叫”旺财”。当你说”旺财,过来!”的时候,如果你们在同一个屋子里,谁的旺财会过来呢?这就可能造成混乱。
在C++编程中,我们也面临类似的问题。当项目变得越来越大,或者当你使用许多第三方库时,不同的代码库中可能会定义相同名称的[函数] (function)、[变量] (variable) 或[类] (class)。例如,你的代码中有一个 print()
函数,而你使用的某个库中可能也有一个 print()
函数。如果直接使用,编译器就不知道你到底想调用哪一个 print()
。
为了解决这种“命名冲突”的问题,C++引入了“命名空间”这个概念。命名空间就像一个“房子”,你可以在里面定义你的函数、变量、类等。这样,即使你的“房子”里有一只叫“旺财”的狗,而你朋友的“房子”里也有一只叫“旺财”的狗,它们也不会相互混淆。你可以说“我的房子里的旺财”,或者“你朋友的房子里的旺财”。
在C++中,我们使用 namespace
[关键字] (keyword) 来定义一个命名空间,并通过 ::
([作用域解析运算符] scope resolution operator)来指明要访问哪个命名空间里的成员。
示例:
1 | namespace MyHouse { // 这是一个命名空间,叫做MyHouse |
2. 什么是嵌套命名空间?
现在我们知道了命名空间的基本概念,那么[嵌套命名空间] (nested namespaces) 又是什么呢?
嵌套命名空间,顾名思义,就是在一个命名空间内部再定义另一个命名空间。这就像你在一个大房子(外层命名空间)里面,又建造了一个小房间(内层命名空间)。这种结构提供了更细粒度的代码组织方式,使得代码的逻辑结构更加清晰,进一步减少命名冲突的可能性。
为什么需要嵌套命名空间?
当你有一个非常大的项目时,仅仅使用一级命名空间可能还不够。例如,你正在开发一个游戏,你可能有一个 Game
命名空间。在这个 Game
命名空间里,你可能需要管理 Graphics
(图形)、Audio
(音频)、Physics
(物理)等子系统。每一个子系统内部又可能有很多自己的函数和类。这时候,你就可以使用嵌套命名空间来组织它们:
1 | namespace Game { // 游戏大命名空间 |
3. 嵌套命名空间的访问规则 (Access Rules)
这是理解嵌套命名空间最关键的部分。记住以下两个核心规则:
规则1:内层命名空间可以直接访问外层命名空间的成员
这就像你在一个房间里,可以直接看到并使用这个房间所属的整个房子里的东西。
- 解释: 如果你在
Hello::World
这个内层命名空间里,你可以直接使用Hello
命名空间里声明的任何变量、函数或类,而不需要加上Hello::
前缀。编译器会自动向上查找。 - 示例: 如果
Hello
命名空间里有一个变量age
,那么在Hello::World
命名空间内部定义的函数,可以直接访问age
。
规则2:外层命名空间需要通过完整路径访问内层命名空间的成员
这就像你在房子的外面,如果你想找到小房间里的东西,你需要先进入房子,然后进入小房间。
- 解释: 如果你在
Hello
命名空间里,或者在全局命名空间 (main
函数通常在全局命名空间) 中,想要访问Hello::World
命名空间里的成员,你必须提供完整的路径,例如Hello::World::成员名称
。你不能直接在Hello
命名空间内访问World
命名空间中的local_var
,因为它不在Hello
的直接作用域内。 - 示例: 如果
Hello::World
命名空间里有一个变量local_var
,那么在Hello
命名空间内部定义的函数,或者在main
函数中,必须使用Hello::World::local_var
来访问它。
4. 详细代码示例
让我们通过一个完整的代码示例来巩固这些概念。这个示例涵盖了您提供的内容中的所有要点,并增加了详细的注释来解释每一步。
1 |
|
代码运行输出:
1 | --- Calling World::say_something() --- |
5. QA 闪卡 (Flash Cards)
为了帮助您记忆和理解,这里有一些问答闪卡:
Q1: C++中命名空间的作用是什么?
A1: 命名空间的主要作用是避免[命名冲突] (name collision),尤其是在大型项目或使用多个库时,它可以帮助组织代码,使同名但不同上下文的实体能够共存。
Q2: 什么是嵌套命名空间?
A2: 嵌套命名空间是指在一个命名空间内部再定义的另一个命名空间。它提供了更精细的代码组织结构。
Q3: 如果我在内层命名空间里,能否直接访问外层命名空间的成员?
A3: 可以。 内层命名空间对其外部的命名空间成员具有直接访问权限。
Q4: 如果我在外层命名空间里,能否直接访问内层命名空间的成员?
A4: 不能。 外层命名空间必须使用完整的命名空间路径(例如 Outer::Inner::member
)来访问内层命名空间的成员。
Q5: 从 main
函数(全局命名空间)访问嵌套命名空间 Hello::World
中的 say_something
函数的语法是什么?
A5: 语法是 Hello::World::say_something();
6. 常见误解或错误
误解1: 认为外层命名空间可以直接访问内层命名空间成员。
- 错误:
namespace Outer { namespace Inner { int val; } void func() { val = 10; } }
这里的val
会导致编译错误。 - 正确做法:
namespace Outer { namespace Inner { int val; } void func() { Inner::val = 10; } }
或者Outer::Inner::val = 10;
。
- 错误:
误解2: 混淆了
using namespace
语句的作用。using namespace Hello;
只能让你直接访问Hello
命名空间中的成员(如age
,do_something()
)。- 错误: 它不会让你直接访问
Hello::World
命名空间中的成员(如local_var
,say_something()
)。你仍然需要写World::say_something()
或Hello::World::say_something()
。 - 如果你想直接访问
Hello::World
中的成员,你需要using namespace Hello::World;
或者同时using namespace Hello;
和using namespace Hello::World;
。但对于初学者,建议始终使用完整的命名空间路径,这样代码更清晰,不易出错。
误解3: 忘记命名空间是用来组织代码的,而不是用来限制访问权限。
- 命名空间的主要目的是避免命名冲突和逻辑分组,而不是实现像
private
或protected
那样的访问修饰符。命名空间中的所有成员默认都是[公共的] (public)。
- 命名空间的主要目的是避免命名冲突和逻辑分组,而不是实现像
错误: 拼写错误或遗漏
::
作用域解析运算符。- 这是最常见的语法错误。记住,每次跨越命名空间边界访问其内部成员时,都需要使用
::
。
- 这是最常见的语法错误。记住,每次跨越命名空间边界访问其内部成员时,都需要使用
编码练习
好的,现在轮到您动手实践了!请完成下面的代码,实现一个简单的嵌套命名空间。
任务:
您需要创建一个名为 Game
的外层命名空间,并在其中嵌套一个名为 Player
的内层命名空间。
- 在
Game
命名空间中,声明一个整型变量max_score
并初始化为1000
。 - 在
Player
命名空间中,声明一个字符串变量name
并初始化为"Hero"
。 - 在
Player
命名空间中,定义一个无参数无返回值的函数display_player_info()
。- 在这个函数内部,打印玩家的
name
。 - 然后,直接访问并打印外层
Game
命名空间中的max_score
。
- 在这个函数内部,打印玩家的
- 在
Game
命名空间中,定义一个无参数无返回值的函数start_game()
。- 在这个函数内部,打印一条消息,例如 “Game started!”。
- 然后,使用完整路径调用内层
Player
命名空间中的display_player_info()
函数。
- 在
main
函数中:- 使用完整路径调用
Game
命名空间中的start_game()
函数。
- 使用完整路径调用
请填写 _______
部分的代码,使其能够正确运行并输出预期的结果。
1 |
|