C++入门(二)

目录

一、内联函数

1、概念

2、特性

二、auto关键字

1、auto简介

2、auto使用细则

3、auto不能推到的场景

三、基于范围的for循环(C++11)

1、范围for的语法

2、范围for的使用条件

四、指针空值nullptr(C++11)

一、内联函数

1、概念

inline 修饰 的函数叫做内联函数, 编译时 C++ 编译器会在 调用内联函数的地方展开 ,没有函数调
用建立栈帧的开销,内联函数提升程序运行的效率。
函数会建立栈帧:
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int ret = 0;
	ret = Add(1, 2);
	cout << ret << endl;
	return 0;
}
调用内联函数的地方展开 ,没有函数调用建立栈帧的开销
inline int Add(int x, int y)
{
	return x + y;
}
int main()
{
	cout << Add(1, 2) << endl;
	return 0;
}

2、特性

1. inline 是一种 以空间换时间 的做法,如果编译器将函数当成内联函数处理,在 编译阶段,会
用函数体替换函数调用 ,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
行效率。
不会建立栈帧,但会使目标文件扩大
inline int Add(int x, int y)
{
	return x + y;
}
int main()
{
	cout << Add(1, 2) << endl;
	return 0;
}

2. inline 对于编译器而言只是一个建议,不同编译器关于 inline 实现机制可能不同 ,一般建
议:将 函数规模较小 ( 即函数不是很长,具体没有准确的说法,取决于编译器内部实现 )
是递归、且频繁调用 的函数采用 inline 修饰,否则编译器会忽略 inline 特性。
编译器会忽视inline特性
inline int Func()
{
	int ret = 0;
	int x1 = 0;
	int x2 = 0;
	int x3 = 0;
	int x4 = 0;
	int x5 = 0;
	int x6 = 0;
	ret += x1;
	ret *= x1;
	ret *= x2;
	ret /= x3;
	ret /= x5;
	return ret;
}
int main()
{
	int ret = Func();
	cout << ret << endl;
	return 0;
}

3、inline 不建议声明和定义分离,分离会导致链接错误。因为 inline 被展开,就没有函数地址了,链接就会找不到。
//声明和定义分离,导致链接错误
//Func.h
#include<iostream>
using namespace std;
inline int Add(int x, int y);//函数声明

//Func.cpp
#include"Func.h"
inline int Add(int x, int y)//函数定义
{
	return x + y;
}


//test.cpp
#include"Func.h"
int main()
{
	cout << "Add(1,2)" << "=" << Add(1, 2) << endl;
	return 0;
}

代码结果:链接出错                                                                                                                                  

二、auto关键字

1、auto简介

auto关键字能够让编译器通过初始化的表达来推导变量的类型。

在早期C/C++auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的 是一直没有人去使用它。C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一 个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

int Test()
{
	return 6;
}
int main()
{
	int a = 1;
	auto b = a;
	auto c = &a;
	double h = 2.222;
	auto i = h;
    //auto w;//错误示范,必须初始化
	char j = 'c';
	auto k = j;
	auto m = Test();
//打印变量类型
	cout << typeid(b).name() << " ";//int类型
	cout << typeid(c).name() << " ";//int* 类型
	cout << typeid(i).name() << " ";//double类型
	cout << typeid(j).name() << " ";//char类型
	cout << typeid(k).name() << " ";//char类型
	cout << typeid(m).name() << " ";//int类型
	return 0;
}
【注意】
使用 auto 定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导 auto
的实际类型 。因此 auto 并非是一种 类型 的声明,而是一个类型声明时的 占位符 ,编译器在编
译期会将 auto 替换为变量实际的类型

2、auto使用细则

1. auto 与指针和引用结合起来使用 。
auto 声明指针类型时,用 auto auto* 没有任何区别,但用 auto 声明引用类型时则必须
&。
int main()
{
	int x = 10;
	auto a = &x;//自动推导出int*类型
	auto* b = &x;//自动推导出int*类型
	auto& c = x;//自动推导出int类型
	cout << typeid(a).name() << endl;//打印结果为int*
	cout << typeid(b).name() << endl;//打印结果为int*
	cout << typeid(c).name() << endl;//打印结果为int
	return 0;
}
2. 在同一行定义多个变量
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译
器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量
int main()
{
	auto a = 1, b = 2;//正确,都是int类型
	auto c = 2.22, d = 3;//错误,auto的声明的同一行,必须是相同类型
}

3、auto不能推到的场景

auto不能作为函数的参数

void Test(auto a)// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
{
	//...//
}

auto不能直接用来声明数组

void Test()
{
	int a[] = { 1,2,3 };
	auto b[] = { 4,5,6 };//此处编译失败,auto不能直接用来声明数组
}

三、基于范围的for循环(C++11)

1、范围for的语法

C++98 中如果要遍历一个数组,可以按照以下方式进行:
int main()
{
	int array[] = { 1,2,3,4,5,6 };
	//让数组中的元素都分别乘以2
	for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
	{
		array[i] *= 2;
	}
	//分别打印数组中的元素
	for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
	{
		cout << array[i] << " ";//打印的结果为2,4,6,8,10,12;
	}
	cout << endl;//换行
	return 0;
}
对于一个 有范围的集合 而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因
C++11 中引入了基于范围的 for 循环。 for 循环后的括号由冒号 分为两部分:第一部分是范
围内用于迭代的变量,第二部分则表示被迭代的范围。
所以上述遍历数组的代码可以改为
int main()
{
	int array[] = { 1,2,3,4,5,6 };
	//让数组中的元素都分别乘以2
	for (auto& e : array)//要引用,因为修改e要对array数组产生影响。不引用,修改e不会改变array数组
	{
		e *= 2;
	}
	//分别打印数组中的元素
	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;//换行
	return 0;
}
注意:与普通循环类似,可以用 continue 来结束本次循环,也可以用 break 来跳出整个循环

2、范围for的使用条件

1、for 循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围 ;对于类而言,应该提供
begin end 的方法, begin end 就是 for 循环迭代的范围。
注意:以下代码就有问题,因为 for 的范围不确定
void TestFor(int array[])//这个数组没有范围
{
	for (auto& e : array)//array范围不确定
		cout << e << endl;
}
2. 迭代的对象要实现 ++ == 的操作 (关于迭代器这个问题,现在大家了解一下就可以了 )

四、指针空值nullptr(C++11)

NULL被定义为0
void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
int main()
{
	f(0);//打印的结果是int
	f(NULL);//打印的结果是int
	f((int*)NULL);//打印的结果是int*
	return 0;
}
程序本意是想通过 f(NULL) 调用指针版本的 f(int*) 函数,但是由于 NULL 被定义成 0 ,因此与程序的
初衷相悖。
C++98 中,字面常量 0 既可以是一个整形数字,也可以是无类型的指针 (void*) 常量,但是编译器
默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转 (void
*)0。
注意:
1. 在使用 nullptr 表示指针空值时,不需要包含头文件,因为 nullptr C++11 作为新关键字引入
2. C++11 中, sizeof(nullptr) sizeof((void*)0) 所占的字节数相同。
3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用 nullptr
  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值