C++示例分析内联函数与引用变量及函数重载的使用

目录
  • 1.内联函数
    • 1.1为什么使用内联函数
    • 1.2语法
  • 2.引用变量
    • 2.1为什么要使用引用变量
    • 2.2语法
    • 2.3对于C语言的改进
  • 3. 函数重载
    • 3.1默认参数
    • 3.2函数重载

1.内联函数

1.1为什么使用内联函数

  • 减少上下文切换,加快程序运行速度。
  • 是对C语言中的宏函数的改进。

1.2语法

#include<iostream>
using namespace std;
inline double square(double x){
    return x*x;
}
int main(){
    cout<<square(2.2)<<endl;
}

其实就是在函数声明或者定义前加上关键字inline

2.引用变量

2.1为什么要使用引用变量

  • 主要用途是用作函数的形参。通过引用变量做参数,函数将使用原始数据,而不是其副本。
  • 高效。

2.2语法

引用实际上就是定义一个别名。看看下面代码:

#include<iostream>
using namespace std;
int main(){
    int a=50;
    int &b=a;//定义并初始化,这里b是a的引用。
    cout<<"a:"<<a<<endl;
    cout<<"b:"<<b<<endl;
    cout<<"address of a:"<<&a<<endl;
    cout<<"address of b:"<<&b<<endl;
    b=100;
    cout<<"a:"<<a<<endl;
    cout<<"b:"<<b<<endl;
    int c=200;
    b=c;//试图将b作为c的引用。行不通。
    cout<<"a:"<<a<<endl;
    cout<<"b:"<<b<<endl;
    cout<<"c:"<<c<<endl;
    cout<<"address of a:"<<&a<<endl;
    cout<<"address of b:"<<&b<<endl;
    cout<<"address of c:"<<&c<<endl;
}

a:50
b:50
address of a:0x61fe14
address of b:0x61fe14
a:100
b:100
a:200
b:200
c:200
address of a:0x61fe14
address of b:0x61fe14
address of c:0x61fe10

a和b的数据地址是一样的,这说明b相当于a的别名,我们改变b的值,也会改变a的值,而且后面我们试图将b转变为c的引用,但是行不通,b=c这个代码做的是赋值语句,相当于a=c.

引用和指针的区别

引用在声明的时候必须初始化

int &b;这句话是不允许的。

引用的本质就是指针常量。因为引用变量一旦初始化就不能更改。

int &b=aint* const p=&a 这两句中b*p是一模一样的。

引用作为函数参数

#include<iostream>
using namespace std;
void swap(int &a,int &b){
    int c;
    c=a;
    a=b;
    b=c;
}
int main(){
int a=2;
int b=3;
swap(a,b);
cout<<a<<b<<endl;
}

可以看出把引用作为参数的函数,只需在声明时,把参数设置成引用即可。

临时变量

试想一下,在参数传递过程中,我们把常数或者错误类型的实参,传给引用参数,会发生什么?这个引用参数会变成这个实参的引用吗?显然不会,因为常数不能修改,引用是错误的,正如int &a=2;会报错一样;错误类型的实参,也不能直接引用。

为了解决这个事,c++允许临时变量的产生。但是只有const引用才会产生临时变量,const引用不允许变量发生赋值。

总结来说,临时变量的产生条件是,在传参给const引用参数时:

实参不是左值.(左值指的是const变量 和 常规变量。)

实参类型不正确且可类型转换。

所以说,为了使得引用参数传递的兼容性和安全性,请多使用const。

#include<iostream>
using namespace std;
double square(const double &a){
    return a*a*a;
}
int main(){
    int a=3;
    cout<<square(3+a)<<endl;
}

可以看出来这里square函数可以接受非左值,类型错误的实参。

你可能觉得这样做很复杂,直接使用按值传参就行了。double square(double a)double square(const double &a),从效果来说,这两一样,但是我们使用第二种传参的好处是高效,试想一下我们同时传一个double类型的变量,const引用传参不需要数据的拷贝,更快。

右值引用

采用 && 来对右值做引用,这么做的目的是用来实现移动语义。

#include<iostream>
using namespace std;
int main(){
    double a=3.1;
    double && b=a*1.2+2.3;
    cout<<b<<endl;
    b=3;
    cout<<a<<endl;
    cout<<b<<endl;
}

6.02
3.1 
3

结构引用

引用非常适合于结构和类

#include<iostream>
using namespace std;
struct apple
{
    string name;
    double weight;
};
apple & swap(apple &a, apple &b){
    apple temp;
    temp=a;
    a=b;
    b=temp;
    return a;
}
int main(){
apple a={"Bob",230};
apple b={"Alice",190};
swap(a,b);
cout<<"a:"<<endl<<"name:"<<a.name<<endl<<"weight:"<<a.weight<<endl<<endl;
cout<<"b:"<<endl<<"name:"<<b.name<<endl<<"weight:"<<b.weight<<endl<<endl;
swap(swap(a,b),b);
cout<<"a:"<<endl<<"name:"<<a.name<<endl<<"weight:"<<a.weight<<endl<<endl;
cout<<"b:"<<endl<<"name:"<<b.name<<endl<<"weight:"<<b.weight<<endl<<endl;
swap(swap(swap(a,b),b),b);
swap(swap(a,b),b);
cout<<"a:"<<endl<<"name:"<<a.name<<endl<<"weight:"<<a.weight<<endl<<endl;
cout<<"b:"<<endl<<"name:"<<b.name<<endl<<"weight:"<<b.weight<<endl<<endl;
}

a:
name:Alice
weight:190

b:
name:Bob
weight:230

a:
name:Alice
weight:190

b:
name:Bob
weight:230

a:
name:Bob
weight:230

b:
name:Alice
weight:190

swap()函数的返回值是一个引用变量,所以swap(swap(swap(a,b),b),b)是合法的,且它等价于swap(a,b)

为何要返回引用?高效。 因为传统返回机制,会把返回结果复制到一个临时位置。 但是应该避免返回 函数终止时不再存在的内存单元引用。例如避免返回临时变量的引用。

2.3对于C语言的改进

  • 用const引用传参传递 代替 按值传递。
  • 对于要修改原始数据的函数,采用引用传参方式。

3. 函数重载

3.1默认参数

默认参数指的是函数调用中省略了实参时自动使用的一个值。

如何设置默认值?必须通过函数原型。 例如这里的void display(int a,int n=999); 这里n=999 就是默认参数 默认参数的作用是,不给这个参数传参时,他会采用默认值。

#include<iostream>
using namespace std;
void display(int a,int n=999);
int main(){
display(1);
display(3,31);
}
void display(int a,int n){
    cout<<a<<endl;
    cout<<n<<endl;
}

1
999
3
31

3.2函数重载

默认参数能让我们使用不同数目的参数调用同一个函数,而函数重载能让我们使用多个同名的函数。

函数重载的关键是函数的参数列表–也称函数特征标。如果两个函数的名字和特征标相同,那么这两个函数就完全相同。C++允许定义名称相同,函数特征标不同的函数,这就是所谓的函数重载。

#include<iostream>
using namespace std;
struct apple{
    string name;
    double weight;
};
void print(int);
void print(double);
void print(char *);
void print(apple &a,string str="apple",double w=100);
int main(){
    int a=2;
    double b=3.14;
    char c[10]="hello!";
    apple d;
    print(a);
    print(b);
    print(c);
    print(d);
    print(d,"Alice",250);
}
void print(int a){
    cout<<"int ="<<a<<endl;
}
void print(double a){
    cout<<"double ="<<a<<endl;
}
void print(char * a){
    cout<<"char* ="<<a<<endl;
}
void print(apple &a,string str,double b){
    a.name=str;
    a.weight=b;
    cout<<"the name:"<<a.name<<endl;
    cout<<"the weight:"<<a.weight<<endl;
}

int =2        
double =3.14  
char* =hello!
the name:apple
the weight:100
the name:Alice
the weight:250

可以看出来print函数有多个重载,现代编译器会根据你传递的参数类型,而选择最匹配的函数。

关于函数重载的一些细节

  1. 类型引用和类型本身视为同一个特征标,例如double cube(double x);double cube(double &x);是不能共存的。
  2. 匹配函数时,会区分const和非const变量,例如 void display(char* a);void display(const char* a);是函数重载。
  3. 请记住是特征标,而不是函数类型使得可以对函数进行重载。例如 long gronk(int,float);double gronk(int,float);是不能共存的。

函数重载的shortcoming

函数重载在实现同函数名多种功能的同时,也应当付出代价。

标准类型转化、强制匹配能力下降。

#include<iostream>
using namespace std;
void print(double);
void print(char *);
int main(){
    int a=2;
    double b=3.14;
    char c[10]="hello!";
    print(a);
    print(b);
    print(c);
}
void print(double a){
    cout<<"double ="<<a<<endl;
}
void print(char * a){
    cout<<"char* ="<<a<<endl;
}

double =2     
double =3.14  
char* =hello!

可以看出来这里print(a)这里a是int类型,编译器会将其类型转化成double,然后调用对应函数。

但是,我们稍微改动一下代码

#include<iostream>
using namespace std;
void print(int);
void print(double);
void print(char *);
int main(){
    int a=2;
    double b=3.14;
    char c[10]="hello!";
    print(a);
    print(b);
    print(c);
    print(12L);
}
void print(int a){
    cout<<"int ="<<a<<endl;
}
void print(double a){
    cout<<"double ="<<a<<endl;
}
void print(char * a){
    cout<<"char* ="<<a<<endl;
}

这段代码中print(12L);会报错,因为12L是long类型的常量,如果我们试着强制匹配会发现,12L既可以转化成int类型,也可以转化成double类型,从而编译器不知道到底调用哪个函数。

不要滥用函数重载

仅当函数基本执行相同的任务,但使用不同类型的数据时,才应当使用函数重载。

到此这篇关于C++示例分析内联函数与引用变量及函数重载的使用的文章就介绍到这了,更多相关C++内联函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++深入讲解函数重载

    目录 函数重载 概念 重载依据 值型别 判断函数重载的规则 名字粉碎-名字修饰 函数重载 概念 在C++中可以为两个或者两个以上函数提供相同的函数名称,只要参数类型不同,或者参数数目不同,参数顺序不同,即参数表不同,那么就认为是函数的重载.(函数名+参数表) // my_max + 参数表 int my_max(int a,int b) { return a > b ? a : b; } char my_max(char a,char b) { return a > b ? a : b; }

  • C++入门语法之函数重载详解

    目录 写在前面 1 函数重载的概念 2 函数重载原理 总结 写在前面 关于C语言的编译与链接不懂的可以看一下下面的文章,先回顾一下以前的知识. 详解C语言的编译与链接 1 函数重载的概念 函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题. //1.函数的参数个数不同 #include <iostream> using namespace std; void

  • C++超详细分析讲解内联函数

    目录 宏函数(带参数的宏)的缺点 inline修饰的函数就是内联函数 内联函数的特点 宏函数和内联函数的区别 宏函数(带参数的宏)的缺点 第一个问题:宏函数看起来像一个函数调用,但是会有隐藏一些难以发现的问题. 例如: #define FUN(x, y) (x * y) printf("%d", add(3, 3 + 2)) //3 * 3 + 2 = 11 以上情况可以通过加 “()” 解决: #define FUN(x, y) (x * y) printf("%d&quo

  • C++浅析函数重载是什么

    目录 前言 函数重载 一些其他问题 2.1 int和char怎么区分 2.2 传值 前言 这是一个非常重要的点 函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数. 这些同名函数的 形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题 或者说,给一个名字赋予第二层意义,一词多义,有点内涵那意思 函数重载 首先C语言不允许定义同名的函数,但是C++可以,原因就涉及到了函数重载 函数重载的要求:函数名相同,参数不同(参数类型不同,

  • C++ 引用与内联函数详情

    目录 引用初阶 什么是引用 为何要有引用 引用指向同一块空间 引用的特性 定义时必须初识化 一个变量可以多次引用 引用一旦引用了一个实例,不能在再引用其他的实例 引用进阶 常引用 权限 临时变量具有常属性 引用的场景 做参数 返回值 引用做返回值 引用不会开辟空间 引用和指针比较 内联函数 为何存在 内联函数 展开短小的函数 内联函数的特性 较大的函数编译器不会发生内联 声明定义一起 引用初阶 引用是C++的特性的之一,不过C++没有没有给引用特意出一个关键字,使用了操作符的重载.引用在C++中

  • C++深入探索内联函数inline与auto关键字的使用

    目录 1.内敛函数 1.1问题引入 1.2内联函数的概念 1.3内敛函数的特性 2.auto关键字 2.1 auto简介 2.2 auto的使用细则 2.3 auto不能推导的场景 2.4 auto与新式for循环使用 1.内敛函数 1.1问题引入 我们在使用C语言中我们都学过函数,我们知道函数在调用的过程中需要开辟栈帧.如果我们需要频繁的调用一个函数,假设我们调用10次Add()函数,那我们就需要建立10次栈帧.我们都知道在栈帧中要做很多事情,例如保存寄存器,压参数,压返回值等等,这个过程是很

  • 深入理解C++内联函数

    目录 内联函数的概念 内联函数和宏 内联函数的特性 总结 内联函数的概念 以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数的使用可以提升程序的运行效率. 举个例子: 在C++中我们通常定义以下函数来求两个整数的最大值: 代码如下: int max(int a, int b) { return a > b ? a : b; } 为这么一个小的操作定义一个函数的好处有: 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它

  • C++深入分析内联函数的使用

    目录 一.常量与宏回顾 二.内联函数 三.内联函数使用注意事项 四.小结 一.常量与宏回顾 C++中的const常量可以替代宏常数定义,如︰ 但是C++中是否有解决方替代宏代码片段呢?这里就要引入内联函数. 二.内联函数 C++中推荐使用内联函数替代宏代码片段 C++中使用 inline 关键字声明内联函数 内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求 C++编译器可以将一个函数进行内联编译 被C++编译器内联编译的函数叫做内联函数 C++编译器直接将函

  • C++示例分析内联函数与引用变量及函数重载的使用

    目录 1.内联函数 1.1为什么使用内联函数 1.2语法 2.引用变量 2.1为什么要使用引用变量 2.2语法 2.3对于C语言的改进 3. 函数重载 3.1默认参数 3.2函数重载 1.内联函数 1.1为什么使用内联函数 减少上下文切换,加快程序运行速度. 是对C语言中的宏函数的改进. 1.2语法 #include<iostream> using namespace std; inline double square(double x){ return x*x; } int main(){

  • C++编程中队内联函数的理解和使用

    函数调用过程 c++经过编译生成可执行程序文件exe,存放在外存储器中.程序启动,系统从外存储器中将可执行文件装载到内存中,从入口地址(main函数起始处)开始执行.程序执行中遇到了对其他函数的调用,就暂停当前函数的执行,并保存下一条指令的地址作为从被调函数返回后继续执行的入口点,保存现场.然后转到被调函数的入口地址执行被调函数.遇到return语句或者被调函数结束后,恢复先前保存的现场,从先前保存的返回地址处继续执行主调函数的其余部分. 内联函数 函数调用需要进行现场保护,以便在函数调用之后继

  • 浅谈内联函数与宏定义的区别详解

    用内联取代宏:1.内联函数在运行时可调试,而宏定义不可以;2.编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义则不会: 3.内联函数可以访问类的成员变量,宏定义则不能: 4.在类中声明同时定义的成员函数,自动转化为内联函数.文章(一)内联函数与宏定义 在C中,常用预处理语句#define来代替一个函数定义.例如: #define MAX(a,b) ((a)>(b)?(a):(b)) 该语句使得程序中每个出现MAX(a,b)函数调用的地方都被宏定义中后面的表达式((a)

  • 非常实用的MySQL函数全面总结详解示例分析教程

    目录 1.MySQL中关于函数的说明 2.单行函数分类 3.字符函数 4.数学函数 5.日期时间函数 6.其它常用系统函数 7.流程控制函数 8.聚合函数 1)聚合函数的功能和分类: 2)聚合函数的简单使用 3)五个聚合函数中传入的参数,所支持的数据类型有哪些? 4)聚合函数和group by的使用"最重要": 1.MySQL中关于函数的说明 "概念":类似java.python中的方法,将一组逻辑语句封装在方法体中,对外暴露方法名: "好处":

  • Go 内联优化让程序员爱不释手

    目录 前言: 什么是内联? 为什么内联很重要? 函数调用的开销 基本知识 Go 中的开销 Go 里的优化 改善优化的机会 进行内联优化 不允许内联 允许内联 这些改进从何而来? 内联的限制 总结 前言: 这是一篇介绍 Go 编译器如何实现内联的文章,以及这种优化将如何影响你的 Go 代码. 什么是内联? 内联是将较小的函数合并到它们各自的调用者中的行为.其在不同的计算历史时期的做法不一样,如下: 早期:这种优化通常是由手工完成的. 现在:内联是在编译过程中自动进行的一类基本优化之一. 为什么内联

  • C++类与对象深入之引用与内联函数与auto关键字及for循环详解

    目录 一:引用 1.1:概念 1.2:引用特性 1.3:常引用 1.4:使用场景 1.5:引用和指针的区别 二:内联函数 2.1:概念 2.2:特性 2.3:面试题 三:auto关键字 3.1:auto简介 3.2:auto使用细则 3.3:auto不能推导的场景 四:基于范围的for循环 4.1:范围for循环的语法 4.2:范围for循环的使用条件 一:引用 1.1:概念 引用不是定义一个新的变量,而是给已经存在的变量取一个别名.注意:编译器不会给引用变量开辟内存空间,他和他的引用变量共用同

  • C++入门(命名空间,缺省参数,函数重载,引用,内联函数,auto,范围for)

    一.C++关键字 C++总共有63个关键字,在入门阶段我们只是大致了解一下就可,在后续博客中会逐渐讲解 二.命名空间 相信学过C++的同学,一定都写过下面这个简单的程序 #include<iostream> using namespace std; int main() { cout<<"hello world"<<endl; return 0; } 我们先来看第二行代码,using namespace std , 这行代码是什么意思呢 ? 这里我们

随机推荐