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

【C++初阶】初识C++:命名空间与引用详解

目录

1.第一个c++程序

2.namespace命名空间

2.1namespace的定义

(1)正常情况下的命名空间

(2)命名空间的嵌套

2.2命名空间的使用

3.C++输入输出

4.缺省参数

5.函数重载

6.引用

6.1引用的概念和定义

6.2引用的特性

6.3引用的使用

6.4const引用

6.5指针和引用的关系

7.inline

8.nullptr


1.第一个c++程序

使用C++输出hello world

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

2.namespace命名空间

2.1namespace的定义

namespace是C++中的一个关键字,可以解决命名冲突问题

定义命名冲突需要使用namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量、函数、类型

namespace的本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量

C++中域有函数局部域、全局域、命名空间域、类域;域影响的是编译时查找一个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间和类域不影响生命周期。(默认只会在局部域和全局域查找,在命名空间域中查找需要指定)

namespace只能定义在全局,并且可以嵌套定义

项目工程中多文件定义同名的namespace会认为是同一个namespace,不会冲突

C++标准库都放在一个叫std(standard)的命名空间中

(1)正常情况下的命名空间

#include<stdio.h> #include<stdlib.h> namespace zsy { // 命名空间可以定义变量/函数/类型 int rand = 10; int Add(int x, int y) { return x + y; } struct Node { struct Node* next; int val; }; } int main() { // 访问全局的rand函数指针 printf("%d\n", rand); // 访问zsy命名空间中的rand printf("%d\n ", zsy::rand); // 这里的::是域作用限定符 printf("%d\n ", ::rand); // 域作用限定符左边什么都不写默认在全局查找 return 0; }

(2)命名空间的嵌套

命名空间可以嵌套

namespace zsy { namespace zsy1 { int rand = 1; int Add(int x, int y) { return x + y; } } namespace zsy2 { int rand = 2; int Add(int x, int y) { return (x + y) * 10; } } } int main() { printf("%d\n",zsy::zsy1::rand); printf("%d\n",zsy::zsy2::rand); printf("%d\n",zsy::zsy1::Add(1,2)); printf("%d\n",zsy::zsy2::Add(1, 2)); return 0; }

2.2命名空间的使用

编译查找一个变量的声明/定义时,默认只会在局部或全局查找,不会到命名空间查找。所以要使用命名空间中定义的变量/函数,有三种方式:

  • 指定命名空间访问(项目中推荐这种方式)
  • using将命名空间中某个成员展开(项目中经常访问的不存在冲突的成员推荐使用)
  • 展开命名空间的所有成员(项目中不推荐,日常练习可用)
namespace zsy { int a = 1; int b = 2; } // 指定命名空间访问 int main() { printf("%d\n", zsy::a); printf("%d\n", zsy::b); return 0; }
// using将命名空间中某个成员展开 using zsy::a; int main() { printf("%d\n", a); printf("%d\n", zsy::b); return 0; }
// 展开命名空间的所有成员 using namespace zsy; int main() { printf("%d\n", a); printf("%d\n", b); return 0; }

3.C++输入输出

<iostream>是Input Output Stream的缩写,是标准的输入输出流库,定义了标准的输入输出对象

std::in是istream类对象,它主要面向窄字符(narrow characters(of type char))的标准输入流

std::out是ostream类对象,它主要面向窄字符的标准输出流

std::end是一个函数,流插入操作时,相当于插入一个换行字符加刷新缓冲区

<<是流插入运算符,>>是流提取运算符。(C语言还用这两个运算符做位移运算左移/右移)

使用C++输入输出更方便,不必像printf/scanf使用时手动指定格式,C++的输入输出可以自动识别变量类型(本质是函数重载),其中最重要的是C++的流能更好的支持自定义类型对象的输入输出

cout/cin/endl等都属于C++标准库,C++标准库都放在一个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去使用

#include<iostream> using namespace std; int main() { int a = 0; double b = 0.1; char c = 'x'; cout << a << " " << b << " " << c << endl; std::cout << a << " " << b << " " << c << endl; return 0; }

4.缺省参数

缺省参数也叫默认参数。缺省参数是声明或定义函数时为函数的参数定义一个缺省值。在调用该函数时,如果没有指定实参,则采用该形参的缺省值,否则使用指定的实参。缺省参数分为全缺省半缺省参数。

全缺省就是全部形参都给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值

带缺省参数的函数的调用,C++规定必须从左到右依次给实参,不能跳跃给实参

函数声明和定义分离时,缺省参数不能在声明和定义中同时出现,规定必须函数声明时给缺省值

#include<iostream> using namespace std; void Func(int a = 0) { cout << a << endl; } int main() { Func(10); // 传参时使用指定的实参 Func(); // 没有传参时使用参数的默认值 return 0; }

全缺省和半缺省

#include<iostream> using namespace std; // 全缺省 void Func1(int a = 10, int b = 20, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl << endl; } // 半缺省 void Func2(int a, int b = 20, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl << endl; } int main() { Func1(); Func1(1); Func1(1, 2); Func1(1, 2, 3); Func2(100); Func2(100, 200); Func2(100, 200, 300); return 0; }

5.函数重载

C++支持在同一作用域中出现同名函数,但要求这些同名函数的形参不同,可以是参数的个数不同或类型不同。这样C++函数调用就出现了多态行为,使用更灵活。C语言不支持同一作用域出现同名函数。

参数相同,返回值不同不构成重载,因为调用时无法区分。

#include<iostream> using namespace std; // 1.参数类型不同 int Add(int a, int b) { cout << "int Add(int a, int b)" << endl; return (a + b); } double Add(double a, double b) { cout << "double Add(double a, double b)" << endl; return (a + b); } //2.参数个数不同 void f() { cout << "void f()" << endl; } void f(int a) { cout << "void f(int a)" << endl; } // 3.参数顺序不同(本质是类型不同) void f(int a, char b) { cout << "void f(int a, char b)" << endl; } void f(char b, int a) { cout << "void f(char b, int a)" << endl; } int main() { Add(10, 20); Add(10.1, 20.2); f(); f(10); f(10, 'a'); f('a', 10); return 0; }

6.引用

6.1引用的概念和定义

引用不是新定义一个变量,而是给已存在的变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

类型& 引用别名 = 引用对象;

#include<iostream> using namespace std; int main() { int a = 0; // b和c是a的别名 int& b = a; int& c = a; //也可以给别名取别名 int& d = b; //四个地址是一样的 cout << &a << endl; cout << &b << endl; cout << &c << endl; cout << &d << endl; return 0; }

6.2引用的特性

引用在定义时必须初始化

一个变量可以有多个引用(可以给别名取别名)

引用一旦引用一个实体,就不能再引用其他实体(不能改变指向)

6.3引用的使用

引用在实践中主要是用于引用传参和引用做返回值中减少拷贝提高效率改变引用对象同时改变被引用对象

引用传参和指针传参功能类似,引用传参相对更方便

#include<iostream> using namespace std; void Swap(int& rx, int& ry) { int tmp = rx; rx = ry; ry = tmp; } int main() { int x = 0, y = 1; cout << x << " " << y << endl; Swap(x, y); cout << x << " " << y << endl; return 0; }

6.4const引用

可以引用一个const对象,但是必须是const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,不能放大。

类似int& rb = a * 3; double d = 12.34; int& rd = d;这样的场景,a*3的结果就保存在一个临时变量中,int& rd也是类似,类型转换过程也会产生中间变量存储中间值,也就是说,rb和rd引用的都是临时变量,而C++规定临时变量具有常性,所以这里触发了权限放大,必须要常引用。

临时变量就是编译器需要一个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名的对象叫做临时对象

int main() { const int a = 10; //编译报错:“初始化”: 无法从“const int”转换为“int &” //这里是对a访问权限的放大 //int& ra = a; int rd = a; // 不属于权限放大,这里是将a的值赋值给rd //正确写法 const int& ra = a; //编译报错:“ra”: 不能给常量赋值 //ra++; int b = 20; const int& rb = b; // 不会影响b本身的访问权限,使用b为可读可写,rb为只读。b和rb地址相同,但权限不同。 //编译报错:“rb”: 不能给常量赋值 //rb++; return 0; }
#include<iostream> using namespace std; int main() { int a = 10; const int& ra = 30; // const引用可以给常量起别名 // 编译报错:“初始化”: 无法从“int”转换为“int &” //int& rb = a * 3; const int& rb = a * 3; double d = 12.34; // 隐式类型转换会产生临时变量 // 编译报错:“初始化”: 无法从“double”转换为“int &” //int& rd = d; // 引用的是d转换为int类型产生的临时变量 const int& rd = d; // 当const引用引用临时对象时,临时对象的生命周期与const引用保持一致 return 0; }

6.5指针和引用的关系

C++中指针和引用在实践中相辅相成,功能有重叠性,但又各有自己的特点,互相不可替代。

指针和引用的底层相同,但在语法上不同

  • 语法概念上引用是一个变量的别名,不开空间;指针是存储一个变量地址,要开空间
  • 引用在定义时必须初始化;指针建议初始化,但语法上不是必须的。
  • 引用在初始化指向一个对象后就不能再引用其他对象;指针可以不断改变指向的对象。
  • 引用可以直接访问被指向的对象;指针需要解引用才能访问指向对象。
  • sizeof中含义不同:引用类型为引用类型的大小,指针始终是地址空间所占字节个数(4或8)
  • 指针容易出现空指针和野指针问题,引用很少出现,引用相对更安全。

7.inline

用inline修饰的函数叫内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要创建栈帧,可以提高效率。

inline对编译器来说只是个建议,加了inline的函数在调用时编译器也可以选择不展开,不同编译器关于inline什么情况展开各不相同,因为C++没有规定这个。inline适用于频繁调用的短小函数,对于递归函数和代码相对多的函数,加上inline也会被编译器忽略。

C语言实现宏函数也会在预处理时替换展开,但宏函数实现很复杂时很容易出错,且不方便调试,C++设计inline目的是替代C的宏函数。

inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开就没有函数地址,链接时会出现报错。

8.nullptr

NULL实际上是个宏

C++中NULL可能被定义为字面量0,或者C中被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时都不可避免会遇到一些麻烦,本想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,调用了f(int x),因此与程序初衷相悖。f((void*)NULL);调用会报错。

C++11中引入nullptr,nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型。

http://www.jsqmd.com/news/696796/

相关文章:

  • Linux操作系统:进程的切换与调度
  • Qwen3-4B-Instruct详细步骤:自定义system prompt与角色设定
  • Github好用项目系列(2)Spec Kit:驱动规范的开发如何颠覆传统的软件开发模式
  • 2026插座买什么牌子的好?安全耐用品牌推荐 - 品牌排行榜
  • 别再滥用keep-alive了!聊聊Vue 3中那些被忽略的缓存策略与性能陷阱
  • 2026年3月美妆加盟品牌推荐,美妆加盟公司 - 品牌推荐师
  • Pixel Language Portal应用场景:开发者社区多语种技术问答智能路由系统
  • 将 Kubernetes 理念引入端侧 AI:探索侠客工坊百万级“数字员工”节点的远程调度与自愈架构
  • 2025_NIPS_EA3D: Online Open-World 3D Object Extraction from Streaming Videos
  • 3分钟搭建自己的电话号码定位系统:免费开源解决方案完全指南
  • GTE-Pro入门必看:GTE-Large训练目标与对比学习损失函数解析
  • 如何构建灵活稳定的Android插件架构:RePlugin的完整实践指南
  • Oumuamua-7b-RP多场景:跨境电商客服质检、日语配音脚本生成、字幕润色
  • Qwen3-TTS-Tokenizer-12Hz保姆级教程:Web界面上传失败的5种排查方案
  • 如何快速解决Blender与3D打印机兼容问题:完整Blender3mfFormat使用指南
  • 代码块 —— 外在定义 及 主要作用
  • Qwen3-ASR-0.6B实战案例:为盲人用户开发语音笔记助手(含方言支持)
  • 机器学习算法核心六问:从原理到实践
  • Node.js项目快速搭建终极指南:Koa-Generator实战手册
  • YOLOv11改进 | Neck篇 | CVPR最新低照度图像增强模块HVI改进YOLOv11(有效涨点)
  • 【高届数机械工程会议】第十二届机械工程、材料和自动化技术国际学术会议(MMEAT 2026)
  • Phi-3.5-Mini-Instruct Streamlit部署优化:模型预加载+缓存加速方案
  • Qianfan-OCR快速上手指南:JPG/PNG/WEBP多格式文档图片解析三分钟搞定
  • 别再死磕PID了!用Python+MPC给机械臂做个‘未来视’控制器(附ROS2实战代码)
  • Qwen3.5-4B-AWQ代码实例:Python调用API+WebUI交互+日志排查全流程
  • Real Anime Z开源价值解读:Z-Image底座+Real Anime Z微调的协同优势
  • 神经网络常见层Numpy封装参考(4):优化器
  • LM多场景落地案例:婚纱摄影公司AI试衣间原型系统构建过程
  • ARGO:开源本地优先AI智能体平台部署与应用全指南
  • FLUX.1-Krea-Extracted-LoRA部署教程:CUDA12.4+PyTorch2.5.0环境兼容性验证