IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++入门·收尾 -> 正文阅读

[C++知识库]C++入门·收尾

在这里插入图片描述

你好,我是安然无虞。

学习网站

推荐给老铁们两款学习网站:
面试利器&算法学习:牛客网
风趣幽默的学人工智能:人工智能学习
首个付费精品专栏:《C++入门核心技术》

写在前面

前面讲到的函数重载和引用是C++入门部分的重点,校招时也很重要,所以大家要牢牢掌握哦,今天的内容就简单多了,加油吧少年们。

内联函数

概念

inline 修饰的函数叫做内联函数,编译时 C++编译器会在调用内联函数的地方直接展开,没有函数压栈的开销,内联函数提升程序运行的效率。

int Add(int left, int right)
{
	return left + right;
}

int main()
{
	int ret = 0;
	ret = Add(1, 2);

	return 0;
}

在这里插入图片描述

上面的Add函数是普通函数,调用时会建立栈帧,压栈等一系列操作,如果频繁调用Add函数,效率上会有一定的损失。
那C语言是如何解决频繁调用像Add这种短小函数导致效率损失的问题呢?在讲解函数重载那节时,编译的预处理过程会发生头文件展开、宏替换、删除注释、条件编译这四个过程,所以这里的答案是定义宏函数,比如:

#define ADD(x, y) ((x) + (y))

C语言是定义宏函数,那C++是如何做的呢?C++是在Add函数前增加 inline 关键字,将其改为内联函数,这样的话在编译期间编译器会用函数体替换函数的调用(在调用内联函数处函数体直接展开)。
在这里插入图片描述
可能老铁会有一个疑惑,为什么C语言都有了宏函数这样的方法,C++还要大费周折去搞一个inline呢?那是因为啊,宏函数极容易写错,比如少加一个括号等,所以C++引入inline解决宏函数晦涩难懂、容易写错的问题,而且宏函数还不支持调试。

特性

  1. inline是一种以空间换时间的做法,省去了调用函数建立栈帧的开销,所以代码很长(一般函数体在10行以内可以,具体取决于编译器)或者有循环/递归的函数都不适宜作为内联函数;
  2. inline 对于编译期而言只是一个建议,编译器会自动优化,如果定义成 inline 的函数体内有循环/递归等,编译器优化时会忽略掉内联;
  3. inline 不建议声明和定义分离,分离会导致链接错误,因为在调用的地方内联函数被展开了,符号表里找不到内联函数地址,所以链接时会找不到

比如下面的代码就会发生链接错误:

//F.h
#include<iostream>
using namespace std;

inline void f(int i);
//F.cpp
#include"F.h"
void f(int i)
{
	cout << i << endl;
}
//main.cpp
#include"F.h"
int main()
{
	f(1);
	return 0;
}

面试题

1、宏的优缺点?
优点:

  • 增强代码的复用性;
  • 提高性能。

缺点:

  • 不方便调试宏;(预编译阶段进行了宏替换)
  • 导致代码可读性差,可维护性差,容易误用;
  • 没有类型安全的检查。

2、C++有哪些技术替代宏?

  1. 常量定义换用const;
  2. 函数定义换用内联函数。

auto关键字(C++11)

编译器支持C++11时才可以使用auto关键字。

auto简介

C++11规定 auto 作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

int test()
{
	return 10;
}

int main()
{
	int a = 10;
	auto b = a;
	auto c = 'a';
	auto d = test();

	cout << typeid(a).name() << endl;//可认为typeid(x).name()返回的是变量x的类型
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;

	//auto e;无法通过编译,使用auto定义变量时必须对其进行初始化
	return 0;
}

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

auto的使用细则

1、auto与指针和引用结合起来使用
auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时必须加&;

int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;

cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;

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

auto a = 1, b = 2;
auto c = 3, d = 4.0;//该行代码会编译失败,因为c和d的初始化表达式类型不同

可能有老铁会疑惑,这样看来auto好像也没有太大的用处,其实不然,不信你看:

//以后我们学习STL时可能会写这样的代码:
std::map<std::string, std::string> dict;
dict["sort"] = "排序";
dict["string"] = "字符串";
std::map<std::string, std::string>::iterator it = dict.begin();
//用auto直接就简短了很多
auto it = dict.begin();

可能老铁现在还看不懂上面的代码,没关系,你现在可以知道我要表达的意思就行了,后面这些都会详细说明。
所以auto一个很重要的意义之一就是:
类型很长时,可以不写,用auto推导

auto不能推导的场景

1、auto不能作为函数的参数

//此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导(给缺省参数也不行)
//因为不知道实参类型具体是什么,建立栈帧时不知道要建立多大
void Test1(auto a)
{}

2、auto不能直接用来声明数组

void Test2()
{
	int a[] = {1, 2, 3};
	auto b[] = {4, 5, 6};
}

3、为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法;
4、auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用。

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

范围for的语法

在C++98中如果要遍历一个数组,可以按照以下方式进行:

int array[] = { 1, 2, 3, 4, 5, 6 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	array[i] *= 2;

for (int* p = array; p < array + sizeof(array) / sizeof(array[0]); p++)
	cout << *p << endl;

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还特容易写错。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号" : " 分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

int array[] = { 1,2,3,4,5 };
//依次自动取array中的数据,赋值给e,自动判断结束
for (auto& e : array)//想想为什么用的是引用?
	e *= 2;

for (auto e : array)
	cout << e << " ";

如果想恢复成原来数组的数据,这样可以吗?

for(auto e : array)
	e \= 2;

这样是错误的,因为e改变不会改变array数组中的值,e只是array数组值的一份拷贝,那怎么办呢?用引用即可(不是拷贝,而是别名)

注意:与普通循环相似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

范围for的使用条件

1、for循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是循环迭代的范围;
注意:以下代码就有问题,因为for的范围不确定。

//这里的array是指针,并不确定其范围,形参传过来的是数组首元素的地址
void TestFor(int array[])
{
	for(auto& e : array)
		cout << e << endl;
}

2、迭代的对象要实现++和==的操作。(关于迭代器,后面会详细讲解)

关于范围for的底层以后会讲解,大家现在了解会用即可。

指针空值nullptr(C++11)

C++98中的指针空值

在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下方式对其进行初始化:

void TestPtr()
{
	int* p1 = NULL;
	int* p2 = 0;
}

NULL实际上是一个宏,在传统的C语言头文件(stddef.h)中,可以看到如下代码:
在这里插入图片描述
可以看到C++将NULL定义成了字面常量0,在实际编程中NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采用何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{
	cout << "f(int)" << endl;
}

void f(int*)
{
	cout << "f(int*)" << endl;
}

int main()
{
	f(0);
	f(NULL);
	f((int*)NULL);
	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。

大厂面试真题

1、关于c++的inline关键字,以下说法正确的是( )
A.使用inline关键字的函数会被编译器在调用处展开
B.头文件中可以包含inline函数的声明
C.可以在同一个项目的不同源文件内定义函数名相同但实现不同的inline函数
D.递归函数也都可以成为inline函数

解析:文章理解之后这道题很简单,选C

2、在( )情况下适宜采用 inline 定义内联函数
A.函数体含有循环语句
B.函数体含有递归语句
C.函数代码少、频繁调用
D.函数代码多,不常调用

解析:跟上一题一样简单

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 10:54:41  更:2022-09-13 10:55:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 11:43:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码