C++基础知识

目录

前言:

命名空间

命名空间的定义

命名空间的使用

c++输入与输出

缺省参数

函数重载

引用

引用的特性

常引用

引用的使用场景

引用做参数

引用做返回值

引用与指针的区别

内联函数

内联函数的特性


前言:

C 语言是结构化和模块化的语言,适合处理较小规模的程序;对于复杂的问题,规模较大 程序,需要高度的抽象和建模时, C 语言则不合适;为了解决软件危机, 20 世纪 80 年代, 计算机界提出了 OOP(object oriented programming:面向对象)思想 ,支持面向对象的程序设计语言 应运而生;
1982 年, Bjarne Stroustrup博士 C 语言的基础上引入并扩充了面向对象的概念,发明了一 种新的程序语言。为了表达该语言与 C 语言的渊源关系,命名为 C++ ,因此: C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计;

命名空间

由于变量 函数 类的名称存在于全局作用域中,会导致命名冲突;

使用命名空间的目的是对标识符的名称进行本地化,以防止命名冲突或名字污染

# include <stdio.h>
# include <stdlib.h> //stdlib.h文件中包含库函数rand()函数
int rand = 20;       //全局变量rand与stdlib.h文件中的库函数rand()发生命名冲突
int main()
{
	printf("%d\n", rand);
	return 0;
}
//代码运行结果 error C2365:"rand":重定义,以前定义是"函数"

命名冲突的场景:

1.  程序员定义的变量与库函数名相冲突;

2.  多人协作同一个大型项目,程序员之间发生函数名命名冲突;

命名空间的定义

程序设计者根据需要指定一些带有名字的空间域,将一些全局实体分别存放于各个命名空间中,从而与其他全局实体分割出来;

定义命名空间的关键字namespace

语法: namespce 命名空间名 { 命名空间成员 }

//命名空间名为Qspace
namespace Qspace 
{
	//定义变量
	int a = 10;
	//定义函数
	int Add(int x, int y)
	{
		return x + y;
	}
	//定义类型
	struct ListNode
	{
		int val;
		struct ListNode* next;
	};
}

 命名空间嵌套定义

namespace Addspace
{
	int Add(int x, int y)
	{
		return x + y;
	}
    //嵌套定义命名空间Subspace
	namespace Subspace
	{
		int sub(int x, int y)
		{
			return x - y;
		}
	}
}

 多个文件定义同名的命名空间,编译器最终会合成同一个命名空间中

//test.h文件
# include <iostream>
namespace MSpace
{
	int Mul(int x, int y)
	{
		return x*y;
	}
}

//test.cpp文件
# include "test.h"
namespace MSpace
{
	int Add(int x, int y)
	{
		return x + y;
	}
	namespace Subspace
	{
		int sub(int x, int y)
		{
			return x - y;
		}
	}
}
int main()
{
	int ret = MSpace::Mul(2, 3);
	printf("%d\n", ret);
	return 0;
}

命名空间的使用

方式一:加命名空间名称及作用域限定符(::) 即命名空间名 :: 命名空间成员名

namespace Qspace 
{
	int a = 10;
	int Add(int x, int y)
	{
		return x + y;
	}
	struct ListNode
	{
		int val;
		struct ListNode* next;
	};
}
int main()
{
	printf("%d\n", Qspace::a);  //变量的访问方式
	int ret = Qspace::Add(2, 3);//函数的访问方式
	printf("%d\n", ret);
	struct Qspace::ListNode node = { 0, NULL };//结构体类型的访问方式
	return 0;
}

方式二:使用using将命名空间中某个成员引入 即using 命名空间名 :: 命名空间成员名

namespace MSpace
{
	int a = 10;
	int b = 20;
}
//using 命名空间名::命名空间成员名
using MSpace::a;

int main()
{
	printf("%d ", a);
	return 0;
}

方式三 :使用using namespace 命名空间名引入即using namespace 命名空间名

using namespace 命名空间名 将整个命名空间展开,使得特定命名空间所有成员名可见,此时使用命名空间下的变量、函数不需要加作用域限定符,使得隔离失效;

namespace Addspace
{
	int a = 10;
	int Add(int x, int y)
	{
		return x + y;
	}
}
using namespace Addspace;
int main()
{
	scanf("%d", &a);
	int ret= Add(2, 3);
	printf("%d\n", ret);
	return 0;
}

c++输入与输出

  • std是C++标准库的命名空间cout为iostream所定义的标准输出对象(控制台)(终端)cin为iostream所定义的标准输入对象(键盘),因此使用cout , cin必须包含< iostream >头文件及按命名空间使用方法使用std;
  • endl(endline)表示换行输出,相当于换行符,包含在<iostream>头文件中;
  • << 流插入运算符(与cout配合使用,可以将输出的变量或者字符串流入到cout中,cout负责输出到终端);  
  • >> 流提取运算符(与cin配合使用,将用户输入的值流入到某变量中);
  • cin以遇到空格键,tab键或者换行符作为分隔符,停止读取;
# include <iostream>
using namespace std;
int main()
{
	cout << "hello world!" << endl;
	return 0;
}

运行结果:

//cin遇到空格键 Tab键 Enter键停止读取
# include <iostream>
using namespace std;
int main()
{
	char a[10] = { 0 };
	cin >> a;
	cout << a << endl;
	return 0;
}

运行结果:

注:cout与cin可以自动识别变量类型

缺省参数

缺省参数是声明或定义函数时为函数的形式参数指定一个默认值(缺省值)

调用该函数时,如果没有指定实参则采用形参的缺省值,否则使用指定的实参;

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

 运行结果:

缺省参数的分类

全缺省参数:函数定义或声明时,为该函数所有形式参数指定缺省值;

半缺省参数:函数定义或声明时,为该函数的部分形式参数指定缺省值,但是缺省值只能从右向左给值,必须连续给值;

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

 运行结果:

# include <iostream>
using namespace std;
void Fun(int a,int b=20,int c=30)//半缺省参数
{
	cout << "a="<< a ;
	cout << "b="<< b ;
	cout << "c="<< c << endl;
}

注:缺省参数不能在函数声明和定义同时出现,若声明与定义皆具有缺省参数,恰巧两个位置提供的值不同,此时编译器无法确定到底该采用那个缺省值,当声明与定义分离时,只能在函数声明处给出缺省参数

函数重载

函数重载:C++允许在同一作用域中声明几个功能类似的同名函数,但是要求同名函数的
形参列表(参数个数 参数类型 类型顺序)不同,返回值无要求;

//参数类型不同
int Add(int a, int b)
{
	return a+b;
}
double Add(double a, double b)
{
   return a+b;
}
//参数个数不同
int Fun(int a);
int Fun(int a,int b);
//形参类型的顺序不同
int Sub(int a, char b);
int Sub(char b, int a);

为什么C++支持函数重载,而C语言不支持函数重载呢?

程序运行时,需要经历如下阶段:预处理 编译 汇编 链接,而在链接阶段会生成符号表,建立函数名与地址一一映射的关系,C语言链接函数地址时,采用函数名寻找函数定义,而对于同名函数无法区分函数地址,但是C++是通过函数修饰规则(如Linux下g++ 修饰规则:

_Z + 函数名字符个数+函数名+参数首字母)来区分,修饰后名字不同,自然支持了重载;

引用

引用不是新定义一个变量,而是 给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量 共用同一块内存空间
语法:   类型&  引用变量名(对象名) = 引用实体
//原变量与引用变量共用同一块内存空间
int main()
{
	int a = 10;
	int& pa = a;
	printf("%p\n", &a);
	printf("%p\n", &pa);
	return 0;
}

运行结果:

注:引用类型与引用实体必须是相同类型;

引用的特性

引用在定义时必须初始化;

int main()
{
	//正确示例
	int a = 10;
	int& pa = a;
	//错误示例
	int b = 20;
	int& pc;//编译时出错
	return 0;
}

一个变量既可以有多个引用又可以给引用变量继续取引用;

int main()
{
	int a = 10;
	int& pa = a;
	int& pb = a;
	int& pc = pa;
	cout << "a=" << a << endl;
	cout << "pa=" << pa << endl;
	cout << "pb=" << pb << endl;
	cout << "pc=" << pc << endl;
	return 0;
}

运行结果:

引用一旦引用一个实体,不能引用其他实体;

 int main()
{
	int a = 10;
	int& pa = a;
	int d = 1;
	// pa变成d的别名?还是d赋值给pa?
	pa = d;//pa的引用实体为a,让引用变量pa引用d
	cout << a << endl;
	return 0;
}

运行结果:

将d的值赋值给pa,又因为pa是a的引用,所以a的值间接变成了1;

常引用

int main()
{
	const int a = 10;
	int& b = a;//错误做法
	const int& b = a;//正确做法
	return 0;
}

变量a由于const修饰具有常属性,不可被修改;而引用变量b与原变量应具有相同属性,不能被修改,但是引用变量放大了权限,导致编译错误;

int main()
{
	//权限可以缩小
	int c = 20;
	const int& d = c;
	const int& e = 10;
	return 0;
}

变量c的属性为可读写,引用变量d的属性为可读,权限缩小并不会导致编译错误;

int main()
{
	int i = 10;
    double j = i;//整型提升
    double& rj = i;//错误做法
	const double& rm = i;//正确做法
	return 0;
}

当发生整型提升时,系统不是直接将其赋值给另外一个变量的,而是会创建一个常量区来存放变量提升后的结果,此时变量具有了常属性,一旦出现权限的放大,必然导致编译错误;

总结:类型转换(整型提升 截断)产生临时变量,临时变量具有常属性;

引用的使用场景

引用做参数

C语言阶段函数通过传址调用,实现通过形参修改实参,由于形参与实参数值上相同,空间上独立,所以实参是形参的临时拷贝;而引用变量在语法上与原变量共用同一块内存空间,若形参采用引用变量的方式,也可达到修改实参;

//指针方式
void Swap1(int* pa, int* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}
//引用方式
void Swap2(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

引用做返回值

void Func()
{
	int c = 0;
	cout << &c << endl;
}
int main()
{
	Func();//Func()函数第一次调用结束,销毁第一次为func()函数所开辟的函数栈帧
	Func();
	return 0;
}

运行结果:

 由于空间可以重复利用,第一次调用Func()函数并为其开辟函数栈帧,并在函数栈帧中为变量c分配空间,当函数运行结束后,该函数所对应的栈空间由操作系统回收,但数据是否被清理是不确定的,当第二次调用Func()函数时,仍然在该地址处创建了c这个变量;

int& Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << "Add(1,2)=" << ret << endl;
	return 0;
}

运行结果:

 ret其实指向的是c那块空间的地址,当c发生了变化,ret也就会随之发生改变;

int& Add(int a, int b)
{
	static int c = a + b;
	return c;
}
int main()
{
	int& ret1 = Add(1, 2);
	cout << "Add(1,2)=" << ret1 << endl;
	int& ret2 = Add(3, 4);
	cout << "Add(3,4)=" << ret2 << endl;
	return 0;
}

运行结果:

当Add()函数运行结束后,由于static修饰的局部变量存放于静态区,出函数作用域并不会被销毁,此时可以引用返回,但是第二次调用Add()函数发生错误,原因为静态成员变量只会被初始化一次

总结:引用做返回值时,返回的数据必须由static修饰或者是存放于堆区的数据或者是全局变量等不会随着函数调用的结束而被销毁的数据;

引用与指针的区别

1. 引用概念上定义一个变量的别名,指针存储一个变量地址;
2. 引用在定义时必须初始化,指针没有要求;
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体;
4. 没有NULL引用,但有NULL指针;
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节);
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小;
7. 有多级指针,但是没有多级引用;
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理;
9. 引用比指针使用起来相对更安全;

内联函数

宏是一种在程序中定义的简单代码替换机制,它们通常用于定义常量或执行重复性操作,与函数不同,宏是在编译时展开的,而不是在运行时调用;

宏的声明方式:

 #define name( parament-list ) stuff
//其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中
//宏函数
# define Add(x,y) ((x)+(y))
int main()
{
	int a = 10;
	int b = 20;
	int ret = Add(10, 20);
	cout << "ret=" << ret << endl;
	return 0;
}

宏的缺点:

1、容易出错,语法细节多;

2、不能调试(预编译阶段进行了替换);

3、没有类型安全的检查;

由于宏的缺点从而产生内联函数替代宏函数;

内联函数:以关键字inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率;

inline int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;
	int ret = Add(10, 20);
	cout << "ret=" << ret << endl;
	return 0;
}

内联函数的特性

  •  inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率;
  • inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性;
  • inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到,由于内联函数所生成的地址不会进入符号表,也就没有函数名与地址一一映射的关系,所以发生链接性错误;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/238063.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器数据恢复—raid5少盘状态下新建raid5如何恢复原raid5数据?

服务器数据恢复环境&#xff1a; 一台服务器上搭建了一组由5块硬盘组建的raid5阵列&#xff0c;服务器上层存放单位重要数据&#xff0c;无备份文件。 服务器故障&分析&#xff1a; 服务器上raid5有一块硬盘掉线&#xff0c;外聘运维人员在没有了解服务器具体情况下&#x…

【教程】制作 iOS 推送证书

​ 目录 证书类型 MAC Key Store 消息推送控制台 制作证书 创建苹果 App ID 使用appuploder制作 .p12文件 创建证书 如需向 iOS 设备推送数据&#xff0c;您首先需要在消息推送控制台上配置 iOS 推送证书。iOS 推送证书用于推送通知&#xff0c;本文将介绍消息推送服务支…

以企业架构为中心的SABOE数字化转型五环法

文章目录 01 传统企业数字化转型面临诸多挑战02 SABOE数字化转型五环法为企业转型破除迷雾 01 传统企业数字化转型面临诸多挑战 即将过去的2023年&#xff0c;chatGPT大模型、数据资产入表等事件的发生&#xff0c;标志着数字经济正在加速发展。数字经济是人类社会继农业经济、…

JS实现返利网注册系统(网页数据验证)

主代码 <!DOCTYPE HTMLPUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"><head><title>返利网注册</tit…

被迫搬家,宽带迁移怎么办?

广州一栋违建烂尾楼&#xff0c;13年里从未停止出租&#xff0c;年年住满人。这栋楼没有贴外墙&#xff0c;裸露的水泥表面都被雨水腐蚀&#xff0c;很多阳台没有建好&#xff0c;只是简单加装了护栏&#xff0c;存在巨大安全隐患。 为什么烂尾楼年年满人呢&#xff1f; 因为它…

重塑未来工作方式,亚马逊云科技re:Invent推出生成式AI助手Amazon Q

亚马逊云科技在re:Invent 2023宣布推出Amazon Q&#xff0c;这是一种新型生成式AI支持的助手&#xff0c;专门用于满足办公场景需要&#xff0c;可以根据客户业务进行定制。客户可以快速获得复杂问题的相关答案、生成内容并采取行动——所有这些都基于客户自身的信息存储库、代…

2 mysql主从复制配置

1、节点以及网络配置 前置条件&#xff1a; 已经在linux上安装好了一主一从或者一主多从的mysql 2、具体配置 主服务器 172.20.0.2 从服务器 172.20.0.3 首先主机mysql配置&#xff1a; 打开mysqld.cnf&#xff1a; 添加如下配置&#xff1a; # 主服务器ID 必须唯一 serve…

改造项目用 开口互感器AKH-0.66/KK-∮24 操作方便,节约时间!

1.产品特点 产品外形美观&#xff0c;安装、接线方便&#xff0c;主要用于电力运维及用电改造项目&#xff0c;一般输出为 AC 5A、 1A 或者毫安等信号&#xff0c;具有体积小、精度高、带载能力强、安装方便等优点&#xff0c;为用户改造项 目节省人力、物力、财力&#xff0c…

深度学习 Day13——P2彩色图片分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU&#xff08;如果设备上支持GPU就使用GPU,否则使用C…

C语言经典错误总结(一)

注&#xff1a;本文是结合《C陷阱和缺陷》所写&#xff01; 一.和 我们都知道在C语言中表示赋值操作符&#xff0c;表示比较&#xff0c;那么你知道为啥单等号为&#xff0c;双等号为比较吗&#xff1f; 这里扩展下&#xff1a;因为在C语言中赋值操作符相对于比较符号较常出…

蛮力算法之深度优先遍历和广度优先遍历——图的深度优先遍历和广度优先遍历,附带案例:迷宫问题及矩阵中传染性传播问题

算法&#xff1a;图的深度优先搜索和广度优先搜索 这两种搜索方法本质上都是基于蛮力法思路 这两种搜索方法对有向图和无向图都适用 文章目录 算法&#xff1a;图的深度优先搜索和广度优先搜索1 图的两种定义方式1.1 邻接矩阵1.2 邻接表 2 图的深度优先遍历3 图的广度优先遍历案…

ArkUI List组件

我们在column中使用foreach循环渲染数据的时候&#xff0c;如果数据过多&#xff0c;超出屏幕高度&#xff0c;会出现隐藏的情况。 class Item {name: stringimage: ResourceStrprice: numberdiscount: numberconstructor(name: string, image: ResourceStr, price: number,dis…

【项目小结】优点分析

一、 个人博客系统 一&#xff09;限制强制登录 问题&#xff1a;限制用户登录后才能进行相关操作解决&#xff1a; 1&#xff09;前端&#xff1a; ① 写一个函数用于判断登录状态&#xff0c;如果返回的状态码是200就不进行任何操作&#xff0c;否则Ajax实现页面的跳转操作…

Python房价分析(二)随机森林分类模型

目录 1 数据预处理 1.1 房价数据介绍 1.2 数据预处理 1.2.1 缺失值处理 1.2.2异常值处理 1.2.3 数据归一化 1.2.4 分类特征编码 2 随机森林模型 2.1 模型概述 2.2 建模步骤 2.3 参数搜索过程 3模型评估 3.1 模型评估结果 3.2 混淆矩阵 3.3 绘制房价类别三分类的…

推荐系统,“广告Match底层技术”中的名词(TDM、HNSW、PQ)

召回&#xff1a;匹配 TDM&#xff1a;"树状深度模型"&#xff08;Tree-based Deep Model&#xff09;&#xff0c;是一种结合了树状结构和深度学习的模型&#xff0c;主要用于解决大规模推荐系统中的候选项生成&#xff08;candidate generation&#xff09;问题。在…

多种DC电源模块的比较和评价

多种DC电源模块的比较和评价 BOSHIDA DC电源模块是一种重要的电子零件&#xff0c;可以将交流电转换为直流电&#xff0c;并为相应的电路提供所需的电能。随着技术的进步&#xff0c;市场上的DC电源模块种类越来越多&#xff0c;不同类型的DC电源模块有着不同的特点和优缺点。 …

数据结构-05-跳表SkipList

1-什么是跳表 跳表SkipList是一种随机化的数据结构&#xff0c;基于并联的链表&#xff0c;实现简单&#xff0c;插入、删除、查找的复杂度均为 O(logN)&#xff08;大多数情况下&#xff0c;因为是实现上是概率问题&#xff09;&#xff0c;因为其性能匹敌红黑树且实现较为简单…

jetpack compose 学习(-)

年底了,无聊的时间总是缓慢的,找个事情做一做,打发打发时间,刚好看到jetpack compose 学习学习,毕竟androidStudio 默认创建的项目都带上了这个,学习网站:https://developer.android.com/jetpack/compose/modifiers?hlzh-cn 1. 首先androidStudio创建一个新项目 喜欢kotlin的,…

面向工业物联网的5G机器学习研究综述

源自&#xff1a;信息与控制 作者&#xff1a;柴浩轩 金曦 许驰 夏长清 摘 要 随着计算机技术不断应用于工业物联网&#xff0c;工业系统中的数据传输愈加需要支持高实时、高可靠、高带宽以及海量连接的特性。传统的网络已经无法满足这些需求&#xff0c;5G网络因其高速率…

ASO优化之如何在应用商城突围

再好的内容没有营销也很难成功。评判一个APP是否在应用市场获得关注的一个重要标准就是下载量。但是&#xff0c;光被人发现你的APP应用是没有用的&#xff0c;还要精确定位有需要的目标群体才能更好的推销出去。在制定合适的优化策略的&#xff0c;一定要对市场行情有一个比较…