C++入门(3):引用,内联函数

简介: C++入门(3):引用,内联函数

一、引用

1.1 引用特性
  1. 引用必须初始化

  1. 一个变量可以有多个引用
  2. 引用一旦引用一个实体,就不能引用其他实体
int main()
{
    int a = 10, C = 20;
    int& b = a;
    b = c; // 赋值?还是b变成c的别名?
    return 0;
}

1.2 常引用

引用权限可以平移或缩小,但是不能放大

int main()
{
    // 情形1
    const int a = 10;
    // int& a1 = a; // error
    const int& a2 = a;
    // 情形2
    // int& b = 10; // error
    const int& b1 = 10;// 10具有常属性,权限平移
    // 情形3
    int c = 10;
    // double& c1 = c;// error,类型不同
    const double& c2 = c;
    // 隐式类型转换过程中,会创建一个具有常属性的临时变量
    return 0;
}
1.3 使用场景
  1. 做参数
#include <iostream>
using namespace std;
void Swap(int& x, int& y)
{
    int tmp = x;
    x = y;
    y = x;
}
int main()
{
    int a = 10;
    int b = 20;
    Swap(a, b);
    return 0;
}
  1. 做返回值

观察以下几个场景。

(a).

#include <iostream>
using namespace std;
int count1()
{
    int n = 0;
    n++;
    return n;
}
int& count2()// 实际上是个错误程序
{
    int n = 0;
    n++;
    return n;
}
int& count3()
{
    static int n = 0;
    n++;
    return n;
}
int main()
{
    int ret1 = count1();
    cout << ret1 << endl;
    int ret2 = count2();
    cout << ret2 << endl;
    int& ret3 = count2();
    // ret3是n的别名,count2函数栈帧销毁后,ret3/n 的值是不确定的
    cout << ret3 << endl;
    cout << ret3 << endl;
    int& ret4 = count3();
    cout << ret4 << endl;
    return 0;
}

(b).

#include <iostream>
using namespace std;
// static
int& Add1(int a, int b)
{
    static int c = a + b;
    return c;
}
int& Add2(int a, int b)
{
    static int c;
    c = a + b;
    return c;
}
int main()
{
    int& ret1 = Add1(1, 2);
    cout << "Add1(1, 2) = " << ret1 << endl;
    Add1(3, 4);
    cout << "Add1(1, 2) = " << ret1 << endl << endl;
    int& ret2 = Add2(1, 2);
    cout << "Add2(1, 2) = " << ret2 << endl;
    Add2(3, 4);
    cout << "Add2(1, 2) = " << ret2 << endl << endl;
    return 0;
}

1.4 传值、传引用效率比较

以值作为参数或返回值类型,在传参和返回期间,函数不会传递实参或将变量本身直接返回,而是传递实参或返回变量的一份临时拷贝。因此用值作为参数或返回值类型,效率非常低下。

1.5 引用和指针的区别

语法概念上,引用是被引用实体变量的别名,并没有开辟新的内存空间。

底层实现上,实际开了空间。引用是按照指针的方式实现的。

二、内联函数

2.1 概念

内联函数是用关键词 inline 修饰的函数,可以代替宏函数(宏函数缺点:1. 语法细节多,易出错;2. 不可调试;3. 没有类型安全检查)。

编译时,C++编译器会在把内联函数在调用位置展开,没有建立函数栈帧的开销,在一定程度上提高程序运行效率。

(在debug模式下,编译器默认不会对代码进行优化,需要通过设置以观察到内联函数)

  1. 右击项目,进入 属性


2.2 特性
  1. inline 是一种以空间换时间的做法,在编译阶段,会用函数体替换函数调用。
  2. inline 对编译器来说只是一个“请求”,编译器可以选择忽略。一般建议:将函数规模较小不是递归频繁调用的函数用 inline 修饰,否则编译器会忽略 inline 特性。
  3. inline 不能声明和定义分离,分离会导致链接错误——inline 被展开就没有函数地址了。

// Func.h
#include <iostream>
using namespace std;
inline void f(int x);
// Func.cpp
#include "Func.h"
void f(int x)
{
    cout << "f(x)" << endl;
}
// test.cpp
#include "Func.h"
int main()
{
    f(10);
    return 0;
}
// error:
// 链接错误:Test.obj : error LNK2019: 无法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z),函数 _main 中引用了该符号

正确做法:

// Func.h
#include <iostream>
using namespace std;
inline void f(int x)
{
    cout << "f(x)" << endl;
}
相关文章
|
6天前
|
程序员 C++
C++模板元编程入门
【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
|
4天前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
4天前
|
存储 自然语言处理 编译器
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
|
4天前
|
小程序 C++
【C++入门 二 】学习使用C++命名空间及其展开
【C++入门 二 】学习使用C++命名空间及其展开
|
4天前
|
人工智能 分布式计算 Java
【C++入门 一 】学习C++背景、开启C++奇妙之旅
【C++入门 一 】学习C++背景、开启C++奇妙之旅
|
12天前
|
C++
C++基础知识(二:引用和new delete)
引用是C++中的一种复合类型,它是某个已存在变量的别名,也就是说引用不是独立的实体,它只是为已存在的变量取了一个新名字。一旦引用被初始化为某个变量,就不能改变引用到另一个变量。引用的主要用途包括函数参数传递、操作符重载等,它可以避免复制大对象的开销,并且使得代码更加直观易读。
|
12天前
|
算法 编译器 C++
C++基础知识(三:哑元和内联函数和函数重载)
在C++编程中,"哑元"这个术语虽然不常用,但可以理解为在函数定义或调用中使用的没有实际功能、仅作为占位符的参数。这种做法多见于模板编程或者为了匹配函数签名等场景。例如,在实现某些通用算法时,可能需要一个特定数量的参数来满足编译器要求,即使在特定情况下某些参数并不参与计算,这些参数就可以被视为哑元。
|
13天前
|
存储 自然语言处理 编译器
|
3天前
|
设计模式 安全 编译器
【C++11】特殊类设计
【C++11】特殊类设计
22 10