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

一些C++入门基础

关键字

图引自  C++ 关键词 - cppreference.com

 命名空间

命名空间解决了C没办法解决的各类命名冲突问题

C++的标准命名空间:std

命名空间中可以定义变量、函数、类型:

namespace CS {//变量char cs408[] = "DS,OS,JW,JZ";int cs = 408;//函数void Func() {cout << "085400" << endl;}//类class student {public:void F() {cout << "bull and horse" << endl;}private:int a = 6;int b = 66;};
}

且命名空间可以嵌套(不常用):

namespace School {int x = 0;namespace CS {//};};

授权

命名空间未展开时,默认不能访问命名空间

全部展开:

using namespace CS;

部分展开(仅可访问部分已展开的变量、函数、类):

using CS::cs408;

或者加上作用域限定符直接访问:

	CS::student st1;st1.F();

合并

如果定义了多个同名的命名空间,会自动合并:

如果合并后有多个同名变量、函数、类型,会出现重定义。

缺省参数

声明或者定义函数时,为参数指定的缺省值,如没有传参时,使用缺省值:

Date(int year = 1, int month = 1, int day = 1) {};

全缺省:

Date(int year = 1, int month = 1, int day = 1) {};

半缺省(部分缺省):

半缺省参数必须从右往左给出,且不能间隔着给。

所以,调用半缺省参数的函数时,传参必须从左往右给出,同样不能间隔。

Date(int year, int month = 1, int day = 1) {};Date(2025);
Date(int year, int month, int day = 1) {};Date(2025,5);

注:在函数声明和定义分离的情况下,不能为声明和定义同时给出半缺省参数,避免声明和定义中的缺省值不同而无法调用。

函数重载

C++允许同一作用域下存在同名函数,条件是:形参的个数 or 类型 or 顺序不同:

Date(int a);
Date(int a, int b);
Date(int a, char b);
Date(char a, int b);

原理

C/C++ 中,一个程序要运行需经历:预处理、编译、汇编、链接;

(每日回顾:C程序预处理(本文包括宏定义)-CSDN博客)

在汇编阶段,对于一个函数,汇编器会为其分配一个地址,并将该地址与函数名关联起来,记录在符号表中;在链接完成之后,会形成完整的符号表。符号表包含了程序中所有符号的名称、地址和属性等信息。

VS中,C和C++的函数名修饰规则对比

 由上图可见,C语言仅在函数名前加 '_' 以在符号表中查找对应函数地址;而C++的函数名修饰中,还与形参有关,这也印证了前文所说函数重载的条件。

特殊情况

函数重载和缺省参数的函数同时存在可能会出现调用歧义:

//无参数 和 全缺省
void F() {};
void F(int a = 1, int b = 2) {};//一个参数 和 半缺省
void F(int a) {};
void F(int a, int b = 2) {};

引用

引用的底层和C指针一样,只是使用更加方便;一个变量的引用,就是给这个已存在的变量取个别名,这个引用与已存在的变量共用同一块内存空间。

int p = 0;
int& pp = p;    // pp是p的引用pp = 1;    // 修改pp,p也会随之修改

特性

1、必须在定义时就初始化;

2、一个变量可以有多个引用:

int p = 0;
int& pp = p;
int& ppp = p;

3、引用被初始化之后,不能再改变指向;

int p = 0;
int q = 1;
int& pp = p;
pp = q;    // 报错,不能再改变指向

使用场景

引用作为参数

void test(int& a){};
int main(){int b = 1;test(b);return 0;
}

引用作为返回值

int& test(int& a){a++;return a;
};
int main(){int b = 1;int ret = test(b);return 0;
}

 上面这段代码,其实test函数中返回的a变量,在出了函数作用域之后已经销毁,只不过我们用ret立刻接收了该引用的值;实际上返回的引用,已经是被释放的空间

所以,如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

效率

使用传值传参和使用值作为返回值类型时,实际上都是实参或者返回变量的一份临时拷贝;所以当值较大时,效率必然低于使用引用传参或者使用引用作为返回值类型。

和指针对比

引用的底层实现,与指针相同,只不过使用时更为方便。

1、引用 在概念上是一个变量的别名,而指针存储地址;

2、引用在定义时必须初始化指向实体,指针不必;

3、引用在初始化引用一个实体后,不能再改变指向,而指针可以;

4、sizeof(引用) 是引用类型的大小,而指针始终是地址所占字节数大小;

5、引用++ 是引用的实体++,而指针++ 是向后偏移;

6、没有多级引用,有多级指针;

7、访问实体方式不同:引用 编译器会处理,而指针需要显式解引用;

8、引用使用起来更安全。

内联函数

以inline修饰的函数为内联函数。

普通函数在调用时,需要建立栈帧;内联函数会在编译时直接展开,没有建立栈帧的开销,提升程序运行效率。

有点像C中的宏函数,只不过宏是完全的只有替换,而内联函数是展开函数体。

inline void test(int a){};

特性

1、以空间换时间,但如果函数体过大,会使文件变大;

2、不同编译器的实现不同,一般编译器会将函数规模较小(10行左右)、且不是递归、且频繁调用的函数,采用inline修饰,否则会忽略。(内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求)

3、inline函数不建议声明和定义分离。因为内联函数展开后,就没有函数地址了,只有声明就会找不到定义,报链接错误。

auto关键字(C++11)

auto作为一 个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。简单来说,auto可以推导当前变量类型。

int a = 0;
auto b = a;
auto c = 'a';

使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto 的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

你不能使用auto来推导未知类型。

auto常用来与范围for、lambda表达式搭配使用。

范围for(C++11)

范围for使得在遍历一个有范围的集合时,更加方便:

int arr[10] = {0};
for (auto a : arr){cout << a << endl;
}

这段代码会依次取数组中所有的数据赋值给 a ,打印;

使用条件

1、for 循环迭代的范围是确定的(下图展示了不确定的范围);

void test(int arr[]){for(auto a : arr){cout << a << endl;}
}

2、迭代的对象要实现++和==的操作。

nullptr

int* p1 = NULL;
int* p2 = 0;

在C的头文件 stddef.h 中,有部分代码:

(条件编译见每日回顾:C程序预处理(本文包括宏定义)-CSDN博客)

#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

NULL实际是一个宏,可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。

但是如果有:

void test(int a)
void test(int* a){};
int main(){test(NULL);
}

那么test(NULL) 到底调用谁?这就出现了问题,C++11中通过引入关键字nullptr 用来初始化空指针。

http://www.xdnf.cn/news/7745.html

相关文章:

  • 记忆化搜索全面解析
  • 基于 STM32 的蔬菜智能育苗系统硬件与软件设计
  • 第41天-Python+Qt四屏播放器开发指南
  • Java实践:调用jar包里的方法
  • 以太网口16路数字量DI输入采集模块 Modbus TCP协议
  • Unreal5 从入门到精通之如何实现 离线语音识别
  • Map更简洁的编码构建
  • 【jzxxoj编程:4420: 寻找自我3】2022-1-30
  • 【免杀】C2免杀技术(七)远程线程注入
  • 使用SQLite Expert个人版VACUUM功能修复数据库
  • 【Linux】第二十一章 管理存储堆栈
  • 如何处理 collation 导致的索引失效 | OceanBase SQL调优实践
  • Redis中的事务和原子性
  • 汽车充电过程中--各个电压的关系(DeepSeek)
  • Dockerfile 实战:编写高效镜像的最佳实践与常见误区
  • AR 开启昆虫学习新视界,解锁奇妙微观宇宙
  • 重构研发效能:项目管理引领软件工厂迈向智能化
  • 汽车生产中的测试台连接 – EtherCAT 转CANopen高效的网关通信
  • PyTorch中单卡训练、DataParallel(DP)和DistributedDataParallel(DDP)
  • Python数据可视化再探——Matplotlib模块 之二
  • 香港科技大学(广州)智能制造理学硕士招生宣讲会——深圳大学专场
  • Android 万能AI证件照 v1.3.2
  • Python打卡训练营day27-函数-装饰器
  • 数据要素如何重构人力资本升级
  • HTML页面渲染过程
  • 【Linux】第二十三章 控制启动过程
  • 汇川PLC通过Profinet转ModbusTCP网关读取西门子PLC数据案例
  • 【c# 中 == 和jave 的== 区别】
  • idea中,git的cherry-pick怎么用
  • Linux:库与链接