6. 内联函数
在函数前加入inline修饰即可将函数变为内联函数。所谓内联函数,就是在编译时C++编译器会将函数体在调用内联函数的地方展开,从而省去了调用函数的栈帧开销,提高程序运行效率。
inline int Add(int a, int b)
{return a + b;
}
int main()
{int c = 0;c = Add(1, 2);return 0;
}
对上述代码,在Debug版本下,我们观察汇编代码,发现仍然调用了函数Add而不是我们希望的内联展开形式。
这是因为内联函数展开后就不可调试了,而Debug版本为了方便我们调试,因此忽略了inline的选项。为了可以看到内联函数的变化,我们可以做出如下设定,再在X86环境下编译程序,这样Debug版本也可以实现内联了。或者使用release版本也可以,release会自动对其进行优化,变为内联展开。
对内联函数做以总结:
①内联函数inline实际上是一种以空间换时间的做法,因为编译器在处理内联函数时会使用函数体替换函数调用,这样会使得目标文件变大,但是省去了调用,提高了效率。
②对于inline的使用,一般将规模小、非递归、频繁调用的函数采取inline修饰。而且inline修饰并不是一定会替换调用,只是向编译器表达内联的希望,具体是否内联要取决于编译器,所以复杂又庞大的函数编译器会忽略内联的请求。
③inline不建议声明与定义分离,这可能会导致需要展开函数时找不到函数体导致链接错误。
7. auto关键字
在C语言中变量一般有三种类型:①auto:自动变量(局部变量),一般省略不写;②static:静态区变量;③extern:外部变量。在C++中,对auto做了新的定义,auto是类型指示符,他可以充当类型声明的占位符,根据初始化类型替换为实际类型。
int func()
{return 9;
}
int main()
{//auto可以根据初始化表达式推导实际类型auto a = 1;auto b = 1.24;auto c = "hello";auto d = func();//typeid(变量).name() 可以打印出符号的类型cout << typeid(a).name() << endl; //intcout << typeid(b).name() << endl; //doublecout << typeid(c).name() << endl; //char const* __ptr64cout << typeid(d).name() << endl; //intreturn 0;
}
在使用auto时需要注意以下几点:
①在使用auto来声明指针变量的时候,*号个数应小于等于指针级数,例如对四级指针,auto后的*小于等于4个都是可以的,但是不可以大于4个。
int main()
{int a = 1;auto p1 = &a;auto* p2 = &a;//auto* p3 = a; //errorauto p3 = &p1;auto p4 = &p3;auto*** p5 = &p3;//auto**** p6 = &p3; //errorcout << typeid(p1).name() << endl; //int * __ptr64cout << typeid(p2).name() << endl; //int * __ptr64cout << typeid(p3).name() << endl; //int * __ptr64 * __ptr64cout << typeid(p4).name() << endl; //int * __ptr64 * __ptr64 * __ptr64cout << typeid(p5).name() << endl; //int * __ptr64 * __ptr64 * __ptr64return 0;
}
②在使用auto声明引用类型时,必须要加&。
int main()
{int a = 1;auto& ra = a;cout << typeid(ra).name() << endl; //intreturn 0;
}
③当使用auto定义多个变量时,该行变量类型应该相同,因为编译器只会对第一个类型推导,然后以此结论定义剩下的变量。
int main()
{auto a = 1, b = 8;//auto c = 'k', d = 1.3; //errorreturn 0;
}
④auto可以作为函数的返回类型,但不可以作为形参的类型。auto也不可以用来声明数组类型。
auto func1()
{return 1;
}
//int func2(auto c) error
//{
// return 2;
//}
int main()
{auto a = func1();cout << typeid(a).name() << endl; //int//auto b = func2(a);//auto arr[3] = {1, 2, 3}; //errorreturn 0;
}
8.基于范围的for循环
基于范围的for循环括号内冒号前是用于迭代的变量,冒号后是迭代的范围,也可以使用continue和break进行控制。暂时只介绍到数组,循环是从数组第一个元素到最后一个。
int main()
{int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };//1.一般的for循环for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)cout << arr[i] << ' ';cout << endl;//2.基于范围的for循环for (int num : arr) //类似于python --- for num in arr:cout << num << ' ';cout << endl;return 0;
}
9.空指针nullptr
在C语言我们所使用的空指针NULL实际上是一个宏,它可能被定义为0,同时也可能被定义为((void*)0)这样一个无类型指针。因此引入nullptr,定义它为((void*)0),代替以往NULL的使命。nullptr在C++中作为关键字存在。
void func(int a)
{cout << "int" << endl;
}
void func(int* a)
{cout << "int*" << endl;
}
int main()
{func(0); //intfunc(NULL); //intfunc((int*)NULL); //int*func(nullptr); //int*
}