目录
inline内联函数
一、内联函数的性质
内联函数(inline)是C++一种重要的构造函数的方法。内联函数可以消除函数调用的开销(即函数压栈),以空间换时间,提高程序运行的效率。在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。具有参数类型检查的功能,相当于宏的上位替代。
- 内联函数一般比较短小,通常不超过10行代码。
- 内联函数不能承载复杂的操作,如循环、递归等。inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等,编译器优化时会忽略掉内联。
- 内联函数不能包含复杂的控制语句,如switch、goto等。
- 内联函数不能包含复杂的数据类型,如结构体、类等。
- 不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
二、内联函数的使用
//头文件中完成定义与声明
inline int ADD(int a = 0, int b = 0, int c = 0)
{
return a + b + c;
}
//在引用该头文件的cpp源文件中直接进行使用
int c = ADD(23, 45, 67);
注:如果在类中直接定义,不需要用inline修饰,编译器自动化为内联函数。
如:
class ClassName
{
//...
//...
//编译器自动化将其化为inline内联函数
int ADD(int a = 0, int b = 0, int c = 0)
{
return a + b + c;
}
//...
//...
}
auto类型修饰符
一、auto类型修饰符的概念
auto是C++中的一种类型说明符,它允许编译器从变量的初始化器中推断出变量的类型。它是在C++11中引入的,用于简化变量的声明,特别是当类型很复杂或很难拼写时。
二、auto类型修饰符的使用
- auto与指针和引用结合起来使用,用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。
- 在同一行定义多个变量当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
- auto会忽略顶层const修饰。
利用typeid().name()函数可以获得表达式的类型
int x = 10;
cout << typeid(x).name() << endl;
auto a = x;
cout << typeid(a).name() << endl;
auto* b = &x;
cout << typeid(b).name() << endl;
auto c = &x;
cout << typeid(c).name() << endl;
auto& d = x;
cout << typeid(d).name() << endl;
三、auto关键字不能使用场景
1.不能作为函数的参数
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{
}
2.不能直接用来声明数组
void TestAuto()
{
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循环的语法
基于范围的for循环是C++11引入的一种新的循环语句,它可以遍历一个序列中的所有元素,而无需使用迭代器或指针。它的语法如下:
for (declaration : range_expression)
{
statement
}
其中,declaration 是一个定义,用于定义一个新变量,该变量将用于存储序列中的每个元素。range_expression 是一个表达式,它表示要遍历的序列。statement 是要执行的语句,它将针对序列中的每个元素执行一次。
二、 基于范围的for循环的前置条件
基于范围的 for 循环只能用于支持迭代器的容器类型。C++ 标准库提供了很多标准容器,如
std::vector
、std::list
、std::map
等,这些容器类型都支持迭代器,因此都可以使用基于范围的 for 循环进行遍历。
使用数组定义的数组可以直接使用基于范围的 for 循环进行遍历,因为数组实际上是一个定长的容器,支持迭代器特性,也就是支持
begin()
和end()
成员函数来返回指向数组首元素和尾后元素的迭代器。
三、基于范围的for循环的使用
例如,以下代码使用基于范围的for循环遍历一个数组:
int arr[] = {1, 2, 3, 4, 5};
for (int i : arr)
{
std::cout << i << ' ';
}
输出:
1 2 3 4 5
在这个例子中,declaration 是 int i,它定义了一个新变量 i,该变量将用于存储数组中的每个元素。range_expression 是 arr,它表示要遍历的数组。statement 是 std::cout << i << ' ',它将打印数组中的每个元素。
使用条件:
for循环迭代的范围必须是确定的,对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。
注意:
用动态开辟的数组,返回值为一个指针,这种指针并不是一个标准容器类型的迭代器,因此不能直接用于基于范围的 for 循环。
代码如下:
int* pa2 = new int[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
cout << *p2 << endl;
for (int& e : pa2)
{
cout << e << " ";
}
cout << endl;
会出现以下错误:
此基于范围的“for”语句需要适合的 "begin" 函数,但未找到。
对于使用 new
创建的动态数组,可以将其封装在一个容器类中,使其具有迭代器特性,从而能够使用基于范围的 for 循环进行遍历。例如,可以使用 std::vector
或 std::array
来封装动态数组:
#include <iostream>
#include <vector>
int main() {
int* arr = new int[5]{1, 2, 3, 4, 5};
std::vector<int> v(arr, arr + 5);
// 或者
// std::array<int, 5> a{arr[0], arr[1], arr[2], arr[3], arr[4]};
for (auto i : v) {
std::cout << i << " ";
}
std::cout << std::endl;
delete[] arr;
return 0;
}