<C++>【入门篇】

  

✨前言✨

🎓作者:【 教主 】

☕博主水平有限,如有错误,恳请斧正。

📌机会总是留给有准备的人,越努力,越幸运!

💦导航助手💦

目录

命名空间

什么是命名空间?

如何创建命名空间?

为什么有命名空间?

如何使用命名空间?

将命名空间全部展开(不推荐)

展开常用的(推荐)

不展开(麻烦)

C++输入&输出

缺省参数

什么是缺省参数?

缺省参数分类

函数重载

引用 

什么是引用?

引用特性

常引用

使用引用时需要注意的问题

指针与引用区别

探索引用底层

内联函数

特性

使用内联函数应注意的问题

内联函数与宏

auto关键字 

auto使用规则 

auto不能推导的场景

基于范围的for循环 

指针空值nullptr




命名空间

什么是命名空间?

命名空间就是一个域,在这个区域我们可以创建变量,创建函数,创建类型,还可以嵌套命名空间。命名空间内的所有内容都属于该命名空间。

如何创建命名空间?

创建命名空间采用 namespace+命名空间名 的形式。

举例如下: 

创建了名为xxx的命名空间,该命名空间内有变量,结构体类型,以及函数。

为什么有命名空间?

命名空间可以将一段代码有效的进行封装,用来处理相同的变量名等问题。

不同文件下的相同名的命名空间会合并,例如在同一个工程下有两个cpp文件,这两个cpp文件中都有命名空间xxx,那么最终编译器会将两个xxx合并为一个。

如何使用命名空间?

  • 将命名空间全部展开(不推荐)

举例如下:

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

 使用格式:using namespace + 命名空间名 即可将命名空间全部展开,直接使用命名空间内的内容,上述代码将命名空间std展开,使用std命名空间中的cout。

缺点:如果两个命名空间都有同一名称的变量等,命名空间全部展开可能会造成重定义

  • 展开常用的(推荐)

举例如下:

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

 使用格式:using 命名空间名::要使用的内容 即可展开该命名空间内常用的内容。

  • 不展开(麻烦)

举例如下:

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

 使用格式:命名空间名::要使用的内容即可。


C++输入&输出

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

 std是C++标准库的命名空间名,其中包含了cout和cin,cout是标准输出对象(控制台),cin是标准输入对象(键盘),endl是C++符号,表示换行输出,它们都包含在头文件<iostream>中。

<<是流插入运算符,>>是流提取运算符。

注意:这里只是简单介绍,其中涉及到运算符重载等知识,后续会继续介绍。


C++会自动识别变量类型

#include<iostream>
using namespace std;
int main()
{
	char a;
	int b;
	float c;

	cin >> a >> b >> c;
	cout << a << b << c;
	return 0;
}

 C++不用像C语言一样设置输入输出的格式等问题,会自动识别。


缺省参数

什么是缺省参数?

缺省参数是在声明和定义函数时为函数的参数指定一个缺省值,调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

#include<iostream>
using namespace std;
void print(int num = 0)
{
	cout << num << endl;
}
int main()
{
	print();
	//未传递实参,采用缺省值

	print(10);
	//传递实参,采用实参
	return 0;
}

 运行结果如下:


缺省参数分类

  • 全缺省参数
void print(int num1 = 1, int num2 = 2)
{
	cout << num1 << num2 << endl;
}
  • 半缺省参数
void print(int num1, int num2 = 2)
{
	cout << num1 << num2 << endl;
}

注意 :

  • 半缺省参数必须从右到左依次给出,不能间隔给
  • 缺省参数不能在定义和声明中同时出现

函数重载

C++允许在同一个作用域中声明几个功能类似的同名函数,这些同名的形参列表(参数个数或类型或类型顺序不同)。

#include<iostream>
using namespace std;

//参数类型不同
int add(int num1, int num2)
{
	return num1 + num2;
}
double add(double num1, double num2)
{
	return num1 + num2;
}

//参数个数不同
void fun()
{
	;
}
void fun(int num)
{
	;
}

//参数顺序不同
void fun(int num, char ch)
{
	;
}
void fun(char ch, int num)
{
	;
}
int main()
{
	add(1, 2);
	add(1.1, 2.2);

	fun();
	fun(1);

	fun(1, 'a');
	fun('a', 1);
	return 0;
}

注意:返回类型不能作为函数重载的依据。 因为调用函数时可以不接收返回值,这时编译器也不清楚究竟在调用哪个函数。


引用 

什么是引用?

引用是一个变量的别名,例如梁山好汉里面的宋江,江湖上人称及时雨,及时雨指的就是宋江。

引用不是新定义一个变量,而是给已经存在的变量取了一个别名,编译器不会给引用开辟内存空间,它和它引用的变量共用一块内存空间。对引用的操作相当于对变量操作。

void test()
{
	int num = 10;
	int& rnum = num;

	rnum = 20;
	cout << num << endl;
}

运行结果如下:

引用特性

  • 引用在定义时必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个变量,不可引用其他变量

常引用

void test()
{
	const int a = 10;
	//int& ra = a;  编译出错,a为常量
	const int& ra = 10;
	
	//int& b = 10;  编译出错,10为常量
	const int& b = 10;

	double d = 1.2;
	//int& rd = d;  编译出错,类型不同

}

使用引用时需要注意的问题

  • 引用权限不能放大
void test()
{
	const int num = 10;
	int& rnum = num;//权限放大
}

 num具有const属性,不能更改,但是引用rnum可读可写的,引用不能放大权限,所以引用也应该声明为const属性。

  • 使用类型转换的引用时加const
void test()
{
	int num = 10;
	float& rnum = num;//报错
}

上述代码会直接报错,原因是num是整形,而float是浮点型,实际上这里num是赋值给一个中间常量temp,再让rnum来引用这个temp,对于常量引用所以要加const。可能有很多人不理解为什么会有一个中间常量?实际上在强制类型转换时也有这样一个中间常量,例如要将int类型转换为float类型,原本的int类型并没有转换为float类型,而是存在一个中间变量来完成。

  • 函数返回值返回局部对象时一定不能用传引用返回,要传值返回

出了函数作用域,局部对象已经销毁,这时传引用可能会引用未知问题

说明

  • 引用作为参数传参时相比指针更加易于理解
  • 引用在传递大对象时效率很高
  • 做返回值时可以修改返回对象

指针与引用区别

  • 引用定义一个变量的别名,指针存储一个变量地址
  • 引用在定义时必须初始化,指针无要求
  • 引用在初始化引用一个实体后,不能再引用其他实体,指针任何时候都可以指向任何一个同类型的实体
  • 没有空引用,但是有空指针
  • sizeof中的含义不同,引用结果是引用类型的大小,而指针是地址空间所占字节数
  • 引用自加是引用实体加一,指针是向后便宜一个类型的大小
  • 指针需要解引用,引用不用
  • 引用更加安全 

探索引用底层

void test()
{
	int num1 = 10;
	int& rnum = num1;

	int num2 = 20;
	int* pnum = &num2;
}

 

将上述代码转为汇编代码后,有如下结果

可能对汇编语言不太了解,但是我们可以看到,指针和引用在汇编层面是一样的。


内联函数

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

特性

  • 内联函数是一种以空间换时间的方法,减少函数调用建立栈帧的开销
  • 内联函数只是一种建议,函数规模较小,不是递归,频繁调用的函数使用inline修饰一般会展开,如果较复杂则编译器会忽视inline
  • 内联函数不建议声明和定义分离,分离会导致链接错误,因为inline被展开,没有函数地址,链接找不到  

使用内联函数应注意的问题

  • 内联函数只是对编译器的一种建议,具体会不会当作内联函数来使用,取决于编译器。
  • 内联函数内部不能有递归、循环,这样如果展开反而会降低效率

内联函数与宏

相同点

  • 提高程序运行效率

不同点

  • 宏不可以调试,内联函数可以调试
  • 宏没有参数类型检查,内联函数检查参数类型

auto关键字 

随着程序越来越复杂,程序中用到的类型也越来越复杂,例如类型:std::map<std::string,std::string>::iterator,类型名过长过复杂,容易写错。

auto是一个新的类型提示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

#include<iostream>
using namespace std;
int fun()
{
	return 10;
}
void test()
{
	int a = 10;
	auto b = a;
	auto c = 'a';
	auto d = fun();

	//auto e;  编译出错,使用auto定义变量时必须进行初始化
}
int main()
{
	test();
	//测试函数
	return 0;
}

auto使用规则 

  • auto与指针和引用结合使用

用auto声明指针类型时,auto* 和auto没有区别,但是用auto声明引用类型时必须加&

  • 同一行定义多个变量

当在同一行声明多个变量时,这些变量必须时相同的类型,否则编译器会报错,因为编译器实际上只对第一个类型进行推导,然后用推导出来的类型定义其他变量

void test()
{
 
    auto a=1,b=2;
    auto c=3,d=4.0; //这行代码会编译失败,c和d的初始化类型不同
}

auto不能推导的场景

  • auto不能作为函数参数
  • auto不能用来声明数组

基于范围的for循环 

for循环后的括号由冒号分为两部分,第一部分表示范围内用于迭代的变量,第二部分表示被迭代的范围。

void test()
{
	int arr[] = { 0,1,2,3,4 };
	for (auto& e : arr)
	{
		e *= 2;
	}
	for (auto e : arr)
	{
		cout << e << " ";
	}

}

运行结果如下:


指针空值nullptr

原来我们使用的是空指针标识符是NULL,实际上NULL是一个值为0的宏,使用时可能出现以下问题

void fun(int)
{
	cout << "fun(int)" << endl;
}
void fun(int*)
{
	cout << "fun(int*)" << endl;
}
void test()
{
	fun(0);
	fun(NULL);
	fun((int*)NULL);
}

运行上述代码结果为:

 我们想让第二个fun()函数调用参数为int*的函数,却调用了参数为int的函数,出现了问题。因此引入nullptr,这里可以理解成nullptr是(void*)0。

欢迎关注,码字不易,希望多多点赞、收

藏哦!抱拳了。

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【 Stack_OverFlow 】

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值