首页 > 编程语言 >C++内联函数、引用、强制类型转换

C++内联函数、引用、强制类型转换

时间:2023-08-23 22:57:02浏览次数:35  
标签:类型转换 函数 int C++ 引用 内联 指针

三、内联函数inline

1、普通函数

普通函数会被编译成二进制指令存储在代码段中,调用语句会生成一条跳转指令,当程序运行到调用语句时,会跳转该函数在代码段中对应的位置执行,执行结束会返回

2、什么是内联函数

内联函数也会被翻译成二进制指令,但调用语句不会生成跳转指令,而是直接把内联函数的二进制指令进行替换,就没有跳转和返回,而是直接执行二进制指令,这种函数称为内联函数

3、显式内联和隐式内联

显式内联:

在函数的返回值前加 inline 该函数就以内联函数的机制调用

隐式内联:

在结构、联合、类中的成员函数会自动被当做内联函数处理

注意:如果在结构、联合、类中声明成员函数,但是在外面定义,则不会当做内联函数处理

实例:

#include <iostream>
using namespace std;

inline void func(void)
{
    cout << "我是显示内联" << endl;    
}

struct Data
{
    void func(void)
    {

    }
    void func1(void);
};

void Data::func1(void);
{

}

int main(int argc,const char* argv[])
{
    for(int i=0; i<10000000; i++)
    {//    适合内联
        func();
    }
}

注意:

  • 函数是否被内联由编译器以及它的优化等级决定,加 inline 只是有可能影响它的决定

  • g++默认优化等级 -O -O1 下所有的内联函数都会当成普通函数处理

在-O2 -O3的优化级别下,甚至普通函数都可能会被当做内联函数处理

  • c99 也支持 inline

4、内联的适用条件

  • 优点:节约了函数传参、跳转、返回的时间,提高代码的运行速度

  • 缺点:当被多个位置调用时,那么二进制指令会被拷贝多份,产生了冗余,导致可执行文件明显增加

  • 适用条件:

①、适合内容简单且同一位置频繁调用的函数

②、不适合内容多、且多个位置、较少调用的函数,因为节约的时间还弥补不过牺牲的空间

③、带有递归属性的函数无法内联,编译器会自动忽略

5、内联函数和宏函数的比较

  • 相同点:都是采用以空间换时间的策略提高程序的运行速度,减少函数调用跳转的耗时

  • 不相同:

①、宏函数不是真正的函数,只是语句替换,不会对参数进行类型检查、没有返回值、安全性低

②、内联函数是真正的函数、严格检查参数类型、有返回值、安全性高

四、引用

引用就是一种取别名的机制

格式:

类型名& 别名 = 数据;

实例:

#include <iostream>
using namespace std;

void func(int& num)
{    
    num++;
    cout << num << " " << &num << endl;    
}

int main(int argc,const char* argv[])
{
    int num = 10;
    int& hehe = num;    //    给num取别名hehe

//    int& xixi;
    hehe = 88;
    cout << num << endl;
    cout << &hehe << " " << &num << endl;    //地址相同

    func(num);
    cout << num << endl;
}

输出:

88
0xbfd67ce8 0xbfd67ce8
89 0xbfd67ce8
89

为什么要使用指针:

1、跨函数共享变量(输出型参数),引用可替代

2、提高传参效率,引用可替代,效率比指针还高,不拷贝字节

3、配合堆内存使用,只能使用指针

4、配合字符串使用,string类可以替代

什么情况下使用引用:

1、跨函数共享变量,引用比指针更安全(无需直接操作地址空间、不存在空引用,也极少出现野引用问题)、也比指针更方便(无需缺地址、解引用)

2、提高传参效率,引用的效率比指针还高,指针最起码还要传递4/8字节的地址编号,但是引用一个字节都不需要传递,但是引用和指针一样都有被修改的风险,因此为了保护目标需要增加const

使用引用需要注意的问题:

1、引用必须初始化,所以不存在空的引用,一个变量可以有多个引用

2、可以引用右值(不能进行取地址),但是必须使用const修饰引用

右值(不能进行取地址):一个表示数据的表达式(如字面常量、函数的返回值、表达式的返回值)

3、引用不能中途更改引用的目标

4、函数的返回值类型可以是引用类型,但不能返回局部变量的引用

int a = 10;
//int& hehe;    编译时会报错
int& hehe = a;
int& xixi = a;

指针与引用的比较(常考面试题)

相同点

1、都可以跨函数共享内存,都可以提高函数传参效率、也需要const保护

2、可以定义数组指针,也可以定义数组引用

int arr[5] = {1,2,3,4,5};
int (*arrp)[5] = &arr;
int (&hehe)[5] = arr;

3、可以定义函数指针,可以定义函数引用

void (*fp)(void) = func;
      fp();
void (&xixi)(void) = func;
      xixi();

实例:

#include <iostream>
using namespace std;

void func(void)
{
    cout << "func" << endl;    
}

int main(int argc,const char* argv[])
{
    /*
    int* arr[5];
    int num = 0;
    int& arr1[1] ={num} ;
    */

    int arr[5] = {1,2,3,4,5};
    int (*arrp)[5] = &arr;
    int (&hehe)[5] = arr;
    for(int i=0; i<5; i++)
    {
        cout << arr[i] << " " << hehe[i] << endl;    
    }

    void (*fp)(void) = func;
    fp();
    void (&xixi)(void) = func;
    xixi();
}

输出:

1 1
2 2
3 3
4 4
5 5
func
func

不同点

1、引用是一种取别名的机制,指针是一种数据类型

2、引用不需要额外存储空间,指针需要4/8字节用于存储内存地址

3、指针可以不初始化,引用必须初始化

4、指针有空指针,但没有空引用

5、指针可以更改指向的目标,但引用不可以

6、指针可以配合堆内存使用,而引用不行

7、可以定义指针数组,但不能定义引用数组

五、C++的强制类型转换

C语言原来的强制类型转换依然可以在C++中继续使用

(新类型)数据

注意:强制类型转换都只是得到一个临时结果,数据原来的类型不会改变

  • 为什么C++要重新设计强制类型转换?

因为C语言的强制类型转换虽然自由度高,但是非常危险

  • 为什么C++之父设计强制类型转换设计得很复杂、使用很麻烦?

因为他认为只有在程序设计不合理的情况下才需要强制类型转换,之所以设计复杂就是不想让程序员使用,而是去反思、重新设计自己的代码

1、静态类型转换

目标类型和原数据类型之间必须有一个方向能够自动类型转换,否则出错

static_cast<目标类型>(原数据)

实例:

#include <iostream>
using namespace std;

int main(int argc,const char* argv[])
{
	int num = 65;
	cout << static_cast<char>(num) << endl;    //输出A

	void* p = NULL;
	static_cast<int*>(p);
	//static_cast<int>(p);    //编译器报错
}

2、动态类型转换

目标类型和原数据类型之间必须存在继承关系,并且目标类型必须是指针类型或引用类型,否则出现错误

dynamic_cast<目标类型>(原数据)

实例:

#include <iostream>
using namespace std;

struct Man
{
	
};

struct Student : public Man
{
	
};

int main(int argc,const char* argv[])
{
	Student s;
	dynamic_cast<Man&>(s);
}

3、去常类型转换

目标类型必须是指针或引用,且除了const属性不同,其它都要相同,否则出现报错

const_cast<目标类型>(原数据)

实例:

#include <iostream>
using namespace std;

int main(int argc,const char* argv[])
{
	const int num = 65;	
	cout << const_cast<int&>(num) << endl;

	int* p = const_cast<int*>(&num);
	//int* p1 = &num;    无法转换
}

4、重解释类型转换

只能把整数转成指针,或者把指针转成整数,否则会出错

reinterpret_cast<目标类型>(原数据)

实例:

#include <iostream>
using namespace std;

int main(int argc,const char* argv[])
{
	int num = 65;
	cout << reinterpret_cast<short*>(num) << endl;    //输出0x41
	cout << reinterpret_cast<unsigned long>(&num) << endl;    //输出3212993788
}

标签:类型转换,函数,int,C++,引用,内联,指针
From: https://www.cnblogs.com/ljf-0804/p/17652976.html

相关文章

  • 在Windows系统中搭建C++刷算法题环境
    下载Docker首先,到Docker官方网站下载适合Windows系统的DockerDesktop并安装。下载Ubuntu镜像使用如下命令安装Ubuntu最新镜像:dockerpullubuntu在镜像中搭建C++编译环境使用如下命令启动一个ubuntu容器:dockerrun-itd--nameubt-cpp-v/d/code/algo:/dataubuntu使......
  • C++虚函数、虚继承:virtual
    ​1.引子在类的继承当中曾经出现过这样一种情况:B、C继承自A,D继承自B和C。 之前提到过,这种情况下,关于类A当中的内容,会被复制成两份给到D,当进行访问的时候,需要指定C或者B,才能够定位到A当中的变量是来自哪里。就像下面这样。​ 代码表示:classA{public:A(int......
  • C++类与对象(二)
    一、类的默认成员函数类内的默认成员函数:用户不显示实现,编译器就会自动生成的成员函数,被称为类的默认成员函数。这些默认成员函数各有各存在的作用。但实际上,很多时候,需要自己写这些成员函数,而不是使用编译器生成的。翻译一下就是,在类内有这样六个成员函数,如果你不写,编译器就会自动......
  • C++笔记
    C++笔记将数字以十六进制输出:cout<<hex<<100<<endl;将数字以八进制输出:cout<<oct<<100<<endl;精度控制include保存a位小数:setprecision(a)将b保留a位:cout<<setprecision(a)<<b<<endl将b保留小数点后a位:cout<<setiosflags(ios::fixed)<<se......
  • C++面向对象笔记(转载自黑马程序员)
    C++核心编程本阶段主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓。1内存分区模型C++程序在执行时,将内存大方向划分为4个区域代码区:存放函数体的二进制代码,由操作系统进行管理的全局区:存放全局变量和静态变量以及常量栈区:由编译器自动分配释放,存放函数的......
  • 支持多数据源联合查询的SQL运行引擎sycnany-SQL使用类型注解和类型转换
    使用介绍安装和配置使用自定义函数sycnany-SQL作为SQL运行引擎并不需要提前定义Schema信息,而且很多数据源本身就是无Schema信息的,例如NoSQL数据库MongoDB,所以从数据源查询数据和运行计算默认直接使用输入数据的类型完成查询和计算,此时查询数据或执行计算可能因数据类型不匹配产......
  • 类和对象(c++对象模型和this指针)
    1.成员变量和成员函数分开储存只有非静态成员变量才属于类的对象上。空对象内存占用空间为1this指针的概念this指针指向被调用的成员函数所属的对象this指针式隐含每个非静态成员函数内的一种指针。this指针不需要定义,直接使用即可。this指针的用途:1.当形参和成员变量同名时,可用thi......
  • 标准C++ -- day03
    一、对象的创建和销毁过程分析对象的创建过程给对象划分内存空间执行初始化列表根据继承表的顺序调用父类的无参构造或者有参构造通过:父类名(val)调用父类的有参构造根据成员变量的定义顺序调用类类型成员的无参构造或者有参构造通过:类类型成员名(val)调用类......
  • Qt/C++开发经验小技巧281-285
    悬停窗体QDockWidget默认在标题栏右键会弹出悬停模块的显示隐藏菜单,如果需要去掉,会发现设置Qt::NoContextMenu或者事件过滤器拦截都是无效的,必须设置dockWidget->setContextMenuPolicy(Qt::PreventContextMenu);。Qt中的布局有个默认的margin边距值和spacing间距值,在没有设......
  • Pybind11:使用C++编写Python模块
    放假摆了一周了。看论文实在不是什么有意思的活。这两天研究了一下Pybind11的用法。使用C/C++和Python混合编程的想法很早就有了,在大一的一次比赛时曾经实践过(虽然不是我写的),当时获得了比较显著的性能提升。但是当时用的是Swig,据队友说Swig对于NumPy的支持极为阴间,当时调试花了好......