当前位置: 首页 > news >正文

C++面向对象程序设计 - 命名空间

        命名空间是ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突。

        在C语言中定义了三个层次的作用域,即文件(编译单元)、函数和复合语句。C++又引入了类作用域,类是出现在文件内的。在不同的作用域中可以定义相同名字的变量,互不干扰,系统能够区别它们。

           例如两个不同的头文件中,命名了的类名相同,同时引入进来会报错【[Error] redefinition of 'class Student'】- 这个错误表明类 Student 被重复定义了。示例如下:

1、s1.h头文件代码:

#include <string>
using namespace std;
// 定义Student学生类
class Student{private:int num;string name;int age;public:Student(int num, string name, int age): num(num), name(name), age(age){}
};

2、s2.h头文件代码:

#include <string>
using namespace std;
// 定义Student学员类
class Student{private:int num;string name;int age;float wage;		//工资public:Student(int num, string name, int age, float wage): num(num), name(name), age(age), wage(wage){}
};

3、主文件代码:

#include "s1.h"
#include "s2.h"
using namespace std;int main(){return 0;
}

        以上代码在编译的时候就会出现名字冲突,为了解决这个问题,ANSI C++增加了命名空间(namespace)。所谓命名空间,实际上一个由程序设计者命名的内存区域,可以根据需要指定一些有名字的空间域,把一些全局实体分别放到各个命名空间中,从而与其他全局实体分隔开来。

        如下代码:

namespace ns1{int a;double b;
}

一、命名空间

        在声明一个命名空间时,花括号内不仅可以包括变量,而且还可以包括以下类型:

  • 变量(可以有初始化)
  • 常量
  • 函数(可以是定义或声明)
  • 结构体
  • 模板
  • 命名空间(在一个命名空间中又定义一个命名空间,即嵌套的命名空间)

示例如下:

#include <iostream>
using namespace std;
namespace ns1{const double PI = 3.1415926;int age = 30;double area(){return 2 * 20 * PI;}namespace ns2{float wage = 1500.0f;}
}int main(){cout <<ns1::PI <<endl;cout <<ns1::age <<endl;cout <<ns1::area() <<endl;cout <<ns1::ns2::wage <<endl;return 0;
}

        运行结果如下图:

二、使用命名空间解决同名冲突

        有了以上的基础后,就可以利用命名空间来解决前端Student类的名字冲突问题了。代码如下:

1、s1.h文件

#include <iostream>
#include <string>
using namespace std;namespace ns1{// 定义Student学生类class Student{private:int num;string name;int age;public:Student(int num, string name, int age): num(num), name(name), age(age){}void print(){cout <<"num:" <<num <<", name:" <<name <<", age:" <<age <<endl;}};
}

2、s2.h文件

#include <iostream>
#include <string>
using namespace std;namespace ns2{// 定义Student学员类class Student{private:int num;string name;int age;float wage;		//工资public:Student(int num, string name, int age, float wage): num(num), name(name), age(age), wage(wage){}void print(){cout <<"num:" <<num <<", name:" <<name <<", age:" <<age <<", wage:" <<wage <<endl;}};
}

3、main主文件

#include "s1.h"
#include "s2.h"
using namespace std;int main(){ns1::Student s1(100, "Tom", 20);ns2::Student s2(1001, "John", 30, 1500.0f);// 打印结果信息s1.print();s2.print();return 0;
}

        运行结果如下图:

三、使用命名空间成员的方法

        在引用命名空间成员时,要用命名空间名和作用域分辨符对命名空间成员进行限定,以区别不同的命名空间中的同名标识符,如:

命名空间名::命名空间成员名

        这种方法是有效的,并保证所引用的实体有惟一的名字。但是如果命名空间名字比较长,尤其在有命名空间嵌套的情况下,为引用一个实体,需要写很长的名字。为此,C++提供了一些机制,能简化使用命名空间成员的手续。

(1)使用命名空间别名

        可以为命名空间起一个别名(namespace alias),用来代替较长的命名空间名。例如下:

#include <iostream>
using namespace std;
namespace ns1{const double PI = 3.1415926;int age = 30;double area(){return 2 * 20 * PI;}namespace ns2{float wage = 1500.0f;}
}int main(){cout <<ns1::PI <<endl;cout <<ns1::age <<endl;cout <<ns1::area() <<endl;// 用别名n2代替ns1::ns2namespace n2 = ns1::ns2;cout <<n2::wage <<endl;return 0;
}

        运行结果还是一样的,如下图:

(2)使用using命名空间成员

        using后面的命名空间成员名必须是由命名空间限定的名字。例如:

#include <iostream>
using namespace std;
namespace ns1{const double PI = 3.1415926;int age = 30;double area(){return 2 * 20 * PI;}
}int main(){// 声明其后出现的变量或函数都是属于命名空间ns1中的using ns1::PI;using ns1::age;using ns1::area;// 此处引用相当于ns1::PI, ns1::age, ns1::area()cout <<PI <<endl;cout <<age <<endl;cout <<area() <<endl;return 0;
}

        当然,前面Student示例如,如使用using则会产生二义性,编译出错,代码如下:

#include <iostream>
#include "s1.h"
#include "s2.h"
using namespace std;int main(){using ns1::Student;Student s1(100, "Tom", 20);// 错误,会出现二义性using ns2::Student;Student s2(1001, "John", 30, 1500.0f);// 打印结果信息s1.print();s2.print();return 0;
}

        所以要注意,在同一作用域中用using声明的不同命名空间的成员中不能有同名的成员。

(3)使用using namespace 命名空间名

        在上面介绍的using命名空间成员,一次只能声明一个命名空间成员,如果在一个命名空间中定义了多个实体,就需要使用多次using命名空间成员名。C++为此提供了using namespace 语句为实现只要用一个语句就能一次声明命名空间中全部成员。示例如下:

#include <iostream>
#include "s1.h"
using namespace std;
using namespace ns1;
int main(){Student s1(100, "Tom", 20);// 打印结果信息s1.print();return 0;
}

        运行结果如下图:

        当然,此用法同“(2)使用using命名空间成员”一样,使用多个命名空间时,当多个命名空间中出现同名时,容易出错。如下代码:

#include <iostream>
#include "s1.h"
#include "s2.h"
using namespace std;
using namespace ns1;
using namespace ns2;int main(){Student s1(100, "Tom", 20);//错误,会出现二义性Student s2(1001, "John", 30, 1500.0f);// 打印结果信息s1.print();s2.print();return 0;
}

        此时编译时会报错【[Error] reference to 'Student' is ambiguous】- 因同一作用域中引入两个命名空间ns1和ns2,其中有同名的类,此时无法判定是哪个命名空间的Student,所以会出现二义性,编译出错。

四、无名的命名空间

        C++还允许使用没有名字的命名空间,如在文件中声明了以下无名命名空间,代码如下:

#include <iostream>
using namespace std;
// 定义无名命名空间
namespace{void test(){cout <<"Test...";}
}int main(){test();return 0;
}

        运行结果如下图:

        由于命名空间没有名字,在其他文件中显然无法引用,它只在本文件的作用域内有效。其作用是更该函数的作用域限定于本文件。C++保留了用static声明函数的用法,同时提供了用无命名空间来实现这一功能,使用无命名空间成员的方法将会取代以前习惯用的对全局变量的静态声明。

五、标准命名空间std

        为了解决C++标准库中的标识符与程序中的全局标识符之间以及不同库中的标识符之间的同名冲突,应该将不同库的标识符在不同的命名空间中定义(或声明)。标准C++库的所有标识符都在一个名为std的命名空间中定义的,或者说标准头文件中函数、类、对象和类模板是在命名空间std中定义的。std是standard(标准)的缩写,表示这是存放标准库的有关内容的命名空间。

        在程序中用到C++标准库时,需要使用std作为限定,代码如下:

std::cout <<"OK" <<endl;

        C++介绍到这里,想必大家已了解命名空间的使用。这就是大家有时看到文件中未引用命名空间std时,标准库中的成员侧需要使用std引用,代码如下:

std::cout <<"Hello World" <<std::endl;

        当引用了命名空间std时,又可以省略掉std,代码如下:

using namespace std;cout <<"Hello World" <<endl;

        所以在标准的C++编程中,应对命名空间std的成员进行声明或限定。

相关文章:

  • stm32编写Modbus步骤
  • Idea jdk配置的地方 启动时指定切换的地方
  • 嵌入式学习
  • 学习分享-分布式 NoSQL 数据库管理系统Cassandra以及它和redis的区别
  • 2024 Java 异常—面试常见问题
  • 华为坤灵路由器初始化开局的注意事项,含NAT配置
  • 使用C#快速搭建一个在windows运行的exe应用
  • python format详解
  • CI/CD实战面试宝典:从构建到高可用性的全面解析
  • UE5.2打包安卓
  • k8s可练习实验分享
  • 1毛钱1百万token,写2遍红楼梦!国产大模型下一步还想卷什么?
  • 【数据库设计】宠物商店管理系统
  • Python第二语言(十四、高阶基础)
  • Internet Download Manager(IDM6.41)安装教程+软件安装包下载
  • #Java异常处理
  • 【EOS】Cleos基础
  • CSS3 变换
  • Django 博客开发教程 8 - 博客文章详情页
  • ES6 ...操作符
  • ESLint简单操作
  • Laravel 中的一个后期静态绑定
  • npx命令介绍
  • oldjun 检测网站的经验
  • spring学习第二天
  • Zepto.js源码学习之二
  • 分布式任务队列Celery
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 入口文件开始,分析Vue源码实现
  • 原生 js 实现移动端 Touch 滑动反弹
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • PostgreSQL之连接数修改
  • 浅谈sql中的in与not in,exists与not exists的区别
  • !$boo在php中什么意思,php前戏
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • # windows 安装 mysql 显示 no packages found 解决方法
  • # 职场生活之道:善于团结
  • #include到底该写在哪
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • $.each()与$(selector).each()
  • (4) PIVOT 和 UPIVOT 的使用
  • (rabbitmq的高级特性)消息可靠性
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (转)iOS字体
  • ****三次握手和四次挥手
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET6 命令行启动及发布单个Exe文件
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .vue文件怎么使用_我在项目中是这样配置Vue的
  • @font-face 用字体画图标