15.面向对象-封装-命名空间
15.1 知识点
命名空间是什么
- 命名空间是为了防止命名冲突而设计的一种机制
- 在声明全局变量、函数、类等内容时,不能在同一作用域中重名
- 有了命名空间,可以在不同命名空间中声明同名内容
- 命名空间就像是一个工具包,在其中可以放置一些相同名字的工具
命名空间的声明和定义
在
.h
和.cpp
中都可以声明和定义命名空间如果在
.cpp
中声明和定义,只能在该文件中使用,无法在其他文件中使用如果在
.h
中声明,可通过引用头文件在其他文件中使用定义可以直接在
.h
中,也可以分开在.cpp
中;建议 .h 中声明,**.cpp** 中定义注意:在
.h
中定义全局变量需要加上extern
关键字extern
在此处的作用是:在命名空间中写全局变量时,如果变量要在多个文件中共享使用,就必须在头文件中写extern
声明,在.cpp
文件中写实际定义
声明语法示例:
namespace 命名空间名
{
变量
函数
类
等等
}
注意:
.h
中声明全局变量需加上extern
- 如果在
.h
中声明、在.cpp
中实现,命名空间中的类方法定义需使用命名空间名::类名::方法
的形式
在 .cpp
中声明和定义:
//如果在cpp中声明和定义 那么只能在该cpp中进行使用
namespace MyNameSpace
{
int i = 10;
void test()
{
cout << "MyNameSpace命名空间中的test方法" << endl;
}
class Test
{
public:
void test()
{
cout << "Test类中的test方法" << endl;
}
};
}
在头文件声明 (.h),在 .cpp
中定义:
#pragma once
#include <iostream>
using namespace std;
namespace MyTool
{
extern int i;
void test();
class Test
{
public:
int i;
void test();
};
}
namespace Math
{
extern float PI;
int add(int a, int b);
class Test
{
public:
int i;
void test();
};
}
#include "MyTool.h"
// 1. 通过 namespace 进行包裹定义
namespace MyTool
{
int i = 10;
void test()
{
cout << "MyTool命名空间中的test方法" << endl;
}
// 类当中的内容定义只能使用命名空间展开方式
}
// 2. 通过 命名空间名::成员 形式指定定义
void MyTool::Test::test()
{
cout << "MyTool命名空间中的Test类中test方法" << endl;
}
float Math::PI = 3.1415926f;
int Math::add(int a, int b)
{
return a + b;
}
void Math::Test::test()
{
cout << "Math命名空间中的Test类中test方法" << endl;
}
命名空间的使用
使用命名空间,除了引用头文件外,还需指定内容来自哪个命名空间
基本语法:
命名空间名::变量名
、命名空间名::函数名
、命名空间名::类名
//MyNameSpace是当前cpp脚本中自己定义的命名空间 所以可以直接用不用#include
// 使用 MyNameSpace 中的变量和方法
cout << MyNameSpace::i << endl; // 10
MyNameSpace::test(); // MyNameSpace命名空间中的test方法
// 使用 MyNameSpace 中的类
MyNameSpace::Test t;
t.test(); // Test类中的test方法
// 使用 MyTool 和 Math(需 #include "MyTool.h")
cout << MyTool::i << endl; // 10
MyTool::test(); // MyTool命名空间中的test方法
MyTool::Test t2;
t2.test(); // MyTool命名空间中的Test类中test方法
cout << Math::PI << endl; // 3.14159
cout << Math::add(5, 2) << endl; // 7
Math::Test t3;
t3.test(); // Math命名空间中的Test类中test方法
或者在文件顶部使用
using namespace 命名空间名;
,调用时可省略前缀注意:不同命名空间中若有同名内容,需明确指定命名空间以免冲突
using namespace MyTool;
cout << i << endl; // 10
test(); // MyTool命名空间中的test方法
Test t4;
t4.test(); // MyTool命名空间中的Test类中test方法
//但是 假如using namespace Math; Math里又有Test这个类
//就会分不清Test是哪个命名空间的 导致报错 就得明确指定了
命名空间可以分散式声明
- 在多个文件中声明同一个命名空间,它们代表同一个空间,成员不得重名。
- 比如声明一个MyTool2.h,里面也声明namespace MyTool是可以的,他和在MyTool.h声明的MyTool命名空间是一个命名空间。注意成员不要重名就行。
MyTool2.h
#pragma once
namespace MyTool
{
extern float f;
void test2();
namespace Inner
{
namespace Inner2
{
extern float f;
void InnerTest();
}
}
}
MyTool2.cpp
#include "MyTool2.h"
#include <iostream>
using namespace std;
float MyTool::f = 2.2f;
void MyTool::test2()
{
cout << "另一个文件中声明的命名空间内容" << endl;
}
使用:
cout << MyTool::f << endl; // 2.2
MyTool::test2(); // 另一个文件中声明的命名空间内容
嵌套命名空间
- 命名空间可无限嵌套声明,类似嵌套类
#pragma once
namespace MyTool
{
extern float f;
void test2();
namespace Inner
{
namespace Inner2
{
extern float f;
void InnerTest();
}
}
}
float MyTool::Inner::Inner2::f = 5.5f;
void MyTool::Inner::Inner2::InnerTest()
{
cout << "MyTool::Inner::Inner2::InnerTest" << endl;
}
cout << MyTool::Inner::Inner2::f << endl; // 5.5
InnerTest(); // MyTool::Inner::Inner2::InnerTest
命名空间别名
- 基本语法:
namespace 自定义名 = 命名空间名;
- 作用:简化复杂的命名空间名
//比如在最上面 namespace customName = MyTool::Inner::Inner2; 整个文件都能使用
// 文件顶部
namespace customName = MyTool::Inner::Inner2;
customName::InnerTest();
// 函数内别名,仅在函数作用域内有效
namespace customName2 = MyTool::Inner::Inner2;
customName2::InnerTest();
匿名命名空间
匿名命名空间让变量、函数、类的作用域仅限当前
.cpp
文件防止与其他文件冲突,实现更好的封装,是
static
的现代替代品只能在当前文件中可见,允许在多个
.cpp
文件中定义同名函数或变量,不会有重定义问题注意:不能在头文件中使用匿名命名空间
// MyTool.cpp
namespace
{
int secret = 10;
}
void print()
{
cout << secret << endl;
}
// MyTool2.cpp
namespace
{
int secret = 99;
}
void print2()
{
cout << secret << endl;
}
// 使用
//顶部下 主函数前
extern void print();
extern void print2();
//调用
print(); // 10,打印 MyTool.cpp 的匿名命名空间的 secret
print2(); // 99,打印 MyTool2.cpp 的匿名命名空间的 secret
15.2 知识点代码
MyTool.h
#pragma once
#include <iostream>
using namespace std;
namespace MyTool
{
extern int i;
void test();
class Test
{
public:
int i;
void test();
};
}
namespace Math
{
extern float PI;
int add(int a, int b);
class Test
{
public:
int i;
void test();
};
}
MyTool.cpp
#include "MyTool.h"
//1.通过namespace进行包裹 定义
namespace MyTool
{
int i = 10;
void test()
{
cout << "MyTool命名空间中的test方法" << endl;
}
//类当中的内容定义 只能使用第二种方式
}
//2.通过类似类一样 命名空间名::变量、函数、类相关 去指定定义
void MyTool::Test::test()
{
cout << "MyTool命名空间中的Test类中test方法" << endl;
}
float Math::PI = 3.1415926f;
int Math::add(int a, int b)
{
return a + b;
}
void Math::Test::test()
{
cout << "Math命名空间中的Test类中test方法" << endl;
}
namespace
{
int secret = 10;
}
void print()
{
cout << secret << endl;
}
MyTool2.h
#pragma once
namespace MyTool
{
extern float f;
void test2();
namespace Inner
{
namespace Inner2
{
extern float f;
void InnerTest();
}
}
}
MyTool2.cpp
#include "MyTool2.h"
#include <iostream>
using namespace std;
float MyTool::f = 2.2f;
void MyTool::test2()
{
cout << "另一个文件中声明的命名空间内容" << endl;
}
float MyTool::Inner::Inner2::f = 5.5f;
void MyTool::Inner::Inner2::InnerTest()
{
cout << "MyTool::Inner::Inner2::InnerTest" << endl;
}
namespace
{
int secret = 99;
}
void print2()
{
cout << secret << endl;
}
Lesson15_面向对象_封装_命名空间.cpp
#include <iostream>
#include "MyTool.h"
#include "MyTool2.h"
using namespace std;
using namespace MyTool;
//using namespace Math;
using namespace MyTool::Inner::Inner2;
namespace customName = MyTool::Inner::Inner2;
extern void print();
extern void print2();
//如果在cpp中声明和定义 那么只能在该cpp中进行使用
namespace MyNameSpace
{
int i = 10;
void test()
{
cout << "MyNameSpace命名空间中的test方法" << endl;
}
class Test
{
public:
void test()
{
cout << "Test类中的test方法" << endl;
}
};
}
int main()
{
#pragma region 知识点一 命名空间是什么
//命名空间是为了防止命名冲突而设计的一种机制
//我们在声明全局变量、函数、类等等内容时,是不能够在同一作用域中重名的
//而有了命名空间,我们可以在不同命名空间中声明同名内容
//
//命名空间就像是一个工具包,在其中可以放置一些相同名字的工具
#pragma endregion
#pragma region 知识点二 命名空间的声明和定义
//在哪里声明和定义:
//命名空间在.h和.cpp中都可以声明和定义
//1.如果在.cpp中声明和定义就只能在该文件中使用,无法在其他文件中使用
//2.如果在.h中声明,那么可以通过引用头文件的形式,在其他文件中使用
// 定义可以直接在.h中也可以分开在.cpp中,建议在.h中声明,在.cpp中定义
// 注意:如果在.h中定义全局变量,需要加上extern关键字
// (extern关键字在此处的作用是 在命名空间中写全局变量时,
// 如果变量要在多个文件中共享使用,就必须在头文件中写 extern 声明,在 .cpp 文件中写实际定义)
//声明语法:
/*namespace 命名空间名
{
变量
函数
类
等等
}*/
//注意:
//1..h中声明 全局变量需要加上 extern
//2..h中声明 .cpp中实现 那么如果是命名空间中的类中的内容需要定义 需要通过 命名空间名::类名::方法定义
#pragma endregion
#pragma region 知识点三 命名空间的使用
//想要使用命名空间,除了引用头文件外
//1.需要指定使用内容来自哪个命名空间
// 基本语法:
// 命名空间名::变量名(函数名或类名等等)
//MyNameSpace是当前cpp脚本中自己定义的命名空间
//
//使用其中的变量和方法
cout << MyNameSpace::i << endl;//10
MyNameSpace::test();//MyNameSpace命名空间中的test方法
//使用其中的类
MyNameSpace::Test t;
t.test();//Test类中的test方法
//MyTool和Math是声明在MyTool.h中的命名空间 需要#include "MyTool.h"
cout << MyTool::i << endl;//10
MyTool::test(); //MyTool命名空间中的test方法
MyTool::Test t2;
t2.test();//MyTool命名空间中的Test类中test方法
cout << Math::PI << endl;//3.14159
cout << Math::add(5, 2) << endl;//7
Math::Test t3;
t3.test();//Math命名空间中的Test类中test方法
//2.或者可以在顶端使用 using namespace 命名空间名;
// 这样可以在使用时省略前面的内容
// 注意:需要注意使用不同命名空间时,其中有同名内容问题时,需要明确来自于哪个命名空间
//比如在最前面using namespace MyTool;
cout << i << endl;//10
test(); //MyTool命名空间中的test方法
Test t4;
t4.test();//MyTool命名空间中的Test类中test方法
//但是 假如using namespace Math; Math里又有Test这个类
//就会分不清Test是哪个命名空间的 导致报错 就得明确指定了
#pragma endregion
#pragma region 知识点四 命名空间可以分散式声明
//如果我们在多个文件中声明同一个命名空间
//那么他们代表的是一个命名空间
cout << MyTool::f << endl;//2.2
MyTool::test2();//另一个文件中声明的命名空间内容
#pragma endregion
#pragma region 知识点五 嵌套命名空间
//命名空间可以类似嵌套类一样无限嵌套声明
cout << MyTool::Inner::Inner2::f << endl;//5.5
InnerTest();//MyTool::Inner::Inner2::InnerTest
#pragma endregion
#pragma region 知识点六 命名空间别名
//基本语法:
//namespace 自定义名 = 命名空间名
//作用:
//可以简化复杂的命名空间名
//比如在最上面 namespace customName = MyTool::Inner::Inner2; 整个文件都能使用
customName::InnerTest();
//下面这个别名在函数内 只在函数语句块有用
namespace customName2 = MyTool::Inner::Inner2;
customName2::InnerTest();
#pragma endregion
#pragma region 知识点七 匿名命名空间
//匿名命名空间让变量、函数、类的作用域只在当前 .cpp 文件中
//防止和其他文件冲突,实现更好的封装,是 static 的现代替代品
//只在当前文件中可见,允许在多个.cpp文件中定义同名函数或变量时,不会有重定义问题
//注意:不能在头文件中使用匿名命名空间
print();//10 打印MyTool.cpp的匿名命名空间的secret变量
print2();//99 打印MyTool2.cpp的匿名命名空间的secret变量
#pragma endregion
}
15.3 练习题
命名空间声明定义时应该注意些什么?
- 虽然在
.h
、.cpp
文件中都能声明和定义命名空间,但一般建议在头文件(.h
)中进行声明,在源文件(.cpp
)中进行定义。因为如果只在cpp中声明定义,无法在其他地方使用了。 - 在头文件中声明全局变量时,需要加上
extern
,并在对应的源文件中进行定义,否则其他翻译单元无法使用。 - 若在同一文件中使用多个命名空间且它们存在同名内容,
using namespace
会引发冲突。此时应明确指出所使用成员所属的命名空间,不要省略前缀。 - 匿名命名空间不要在.h中声明和定义,它的作用是类似集群式 static,只能在.cpp中声明和定义,可以使其中的内容只在当前cpp中生效。
命名空间冲突示例及修改
下面代码演示了在同时 using namespace A;
和 using namespace B;
时对同名变量 x
的冲突:
namespace A {
int x = 5;
}
namespace B {
int x = 10;
}
using namespace A;
using namespace B;
int main() {
std::cout << x << std::endl;
}
该代码无法通过编译,因为编译器无法判断 x
属于 A::x
还是 B::x
。应改为显式指定命名空间:
namespace A {
int x = 5;
}
namespace B {
int x = 10;
}
int main() {
std::cout << A::x << std::endl; // 5
std::cout << B::x << std::endl; // 10
}
15.4 练习题代码
Lesson15_练习题.cpp
#include <iostream>
namespace A {
int x = 5;
}
namespace B {
int x = 10;
}
using namespace A;
using namespace B;
using namespace std;
int main()
{
#pragma region 练习题一
//请简单总结命名空间声明定义时应该注意些什么?
//
//1.虽然 cpp 和 .h以及.cpp 中都能声明和定义
// 但是我们一般建议 分开在.h和.cpp中进行声明和定义,因为如果只在cpp中声明定义,无法在其他地方使用了
//2.在.h中声明时,全局变量需要加上 extern,并且需要在cpp中进行定义
//3.在同一文件中使用多个命名空间时,如果他们其中有同名的内容,在使用 using namespace 时需要注意同名冲突
// 我们一般需要明确使用的内容来自哪个命名空间,不要去省略
//4.匿名命名空间不要在.h中声明和定义,它的作用是类似集群式 static,只能在.cpp中声明和定义
// 可以是其中的内容只在当前cpp中生效
#pragma endregion
#pragma region 练习题二
/*namespace A {
int x = 5;
}
namespace B {
int x = 10;
}
using namespace A;
using namespace B;
int main() {
std::cout << x << std::endl;
}
上述代码能否通过编译?如果不能,哪里错了?如何修改?*/
//不能 需要明确哪个命名空间
cout << A::x << endl;//5
cout << B::x << endl;//10
#pragma endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com