第一章:03从c语言到c++
代码运行环境
本节教程所有代码都是在win11系统,Qt 5.12.12版本,mingw编译工具环境编写运行。创建的工程类型为Qt Console Application。
1.内联函数
程序执行函数调用,系统要建立栈空间,保护现场,传递参数以及控制程序执行。有些时候函数功能本身很简单,代码很短,但使用频率很高,频繁切换会花费很多时间。为了减少函数调用切换的时间,一个解决方法就是不使用函数调用,直接将函数写入大方法中。这种方式的缺点就是每个需要调用的地方都要写,代码重复。因此引入内联思想,由编译器在编译过程中将函数写入。
内联函数的定义是在定义函数时使用修饰词 inline
//编译器优化了,会将简单函数直接优化为内联函数
//下面的代码无法在qt中测试内联函数与一般函数的执行区别
#include <QCoreApplication>
#include <iostream>
#include <ctime>
using namespace::std;
inline int max(int a, int b) //在编译过程中,就会将这段代码添加进main函数
{
return a >b ? a : b;
}
int testMax(int a, int b)
{
int maxa = max(a,b);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
clock_t start = clock();
for(int i = 0; i< 10000; i ++)
{
int aa = testMax(5,8);
}
clock_t finish = clock();
double elapsedTime = double(finish - start) / CLOCKS_PER_SEC;
cout << "Elapsed time: " << elapsedTime << " s\n";
return a.exec();
}
1.1内联函数与带参数宏的区别
1.内联函数在编译时期在调用的地方展开,而宏是在预处理时期进行替换
2.内联函数在调用时期要求形参和实参类型要一致,有一个类型判断的过程,而且内联函数会先对实参表达式进行求值,然后传给形参。宏调用就是直接将实参与形参进行替换
3.c++建议简单函数使用inline(内联)
//编译器优化了,会将简单函数直接优化为内联函数
//下面的代码无法在qt中测试内联函数与一般函数的执行区别
#include <QCoreApplication>
#include <iostream>
#include <ctime>
#define MAX(a, b) (a) > (b) ? (a) : (b) //宏定义,不需要参数类型
using namespace::std;
inline int max(int a, int b) //内联函数
{
return a >b ? a : b;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
clock_t start = clock();
for(int i = 0; i< 10000; i ++)
{
int aa = max(5,8);
}
clock_t finish = clock();
double elapsedTime = double(finish - start) / CLOCKS_PER_SEC;
cout << "Elapsed time: " << elapsedTime << " s\n";
return a.exec();
}
2.新的类型转换运算符
新式类型转换主要有这几种:const_cast(expr),static_cast(expr),reinterpret_cast(expr) dynamic_cast(expr),这个转换无法用旧式语句来进行转换
旧式转换:(T)expr, T(expr)
2.1 const_cast(expr)
const_cast(expr),这是用来移除对象的常量性(cast away the constness)
const_cast(expr)一般用于指针或者引用,移除常量性的目的不是修改它的内容,通常是为了让函数能够接受这个参数
#include <QCoreApplication>
#include <iostream>
using namespace::std;
//引入一个函数,让其能使用const类型的参数
void fun(int& var)
{
cout << var << endl;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const int var = 100;
// int * p = &var; 这种写法是错误的,&var是 const int*,这无法转为 int*
//使用const_cast<T>(expr)转换运算符
int *p = const_cast<int*>(&var); //这是正确写法,去除了const int* 的const属性
*p = 200; //这也是正确的,能修改
cout << var << endl; //但是var = 100
//查看 *p的地址与var的地址,发现两者其实是一个地址
cout << p << endl;
cout << &var << endl;
int &pp = const_cast<int&>(var); // 这是引用的用法
pp = 500;
cout << var<< endl; //还是无法修改var的值
// fun(var); 这是错误的
fun(const_cast<int&>(var)); //将const属性去掉,函数就能调用var这个变量,需要注意 输出的值为200,这是一个临时变量
return a.exec();
}
2.2 static_cast(expr)
编译器隐式执行的任何类型转换都可用static_cast(expr)完成。当一个较大的算术类型赋值给较小的类型时,可以用static_cast进行强制转换。
可以将void*指针转为某一类型的指针
可以将基类指针转换为派生类指针
无法替代const_cast,不能将const转为非const类型
#include <QCoreApplication>
#include <iostream>
using namespace::std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
short b = 10;
int aa = b; //隐式转换
double pi = 3.14;
short cc = pi; //较大的算术类型赋值给较小的类型,这个写法没问题
cout << cc << endl;
short dd = static_cast<short>(pi);
cout << dd << endl;
//将void*指针转为某一类型的指针
void*p = &aa;
int* p2 = static_cast<int*>(p);
cout << *p2 << endl;
return a.exec();
}
2.3 reinterpret_cast(expr)
reinterpret_cast(expr)通常为操作上的位模式提供较低层的重新解释,也就是数据以二进制式重新解释。
#include <QCoreApplication>
#include <iostream>
#include <cstdint> // 需要包含这个头文件来使用 uintptr_t
using namespace::std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int aa = 10;
int* i = &aa;
cout << *i << endl;
char *p = "test a sample";
uintptr_t ii;
ii = reinterpret_cast<uintptr_t>(p);
// int ii;
// 下面的写法是错误的,会提示精度不够,因为int是4字节,指针是8字节
//若系统是32位的则不会出错
// ii = reinterpret_cast<int>(p);
cout << ii <<" " << p<< endl;
return a.exec();
}