zoukankan      html  css  js  c++  java
  • 引用和内联函数

    一 内联函数

      内联函数是C++为提高程序运行速度所做的一项改进。

      编译过程的最终产品是可执行程序(由一组机器语言指令组成)。程序运行时,操作系统将这些指令载入到计算机内存中,因此每条指令都有特定的内存地址。

      常规函数调用过程---程序跳到函数的地址,并在函数结束时返回。即,程序执行到函数调用指令时,将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈,跳到标记函数起点的内存单元,执行函数代码,返回值放入寄存器中,然后跳回到地址被保存的指令处(这与阅读文章时停下来看标注,并在阅读完标注后返回到之前阅读的地方类似)

      内联函数是将相应的代码替换函数调用。优点是内联函数运行速度比常规函数稍快,缺点是占用更多内存。

      要使用内联函数,需要:

      (1)在函数声明前加上关键字inline

      (2)在函数定义前加上关键字inline

    注:内联函数不能递归

      另:内联函数与宏的区别

    内联函数参数传递方式与常规函数一样,宏是简单的文本替换来完成

    例如:

    inline double square(double x) {return x*x; }

    #define SQUARE(X) X*X

    SQUARE(0.5)  //->0.5*0.5

    SQUARE(4.5+7.5) //4.5+7.5*4.5+7.5

    SQUARE(c++) //c++*c++

    二 引用变量

    引用时已定义的变量的别名(如土豆,又叫马铃薯)。引用的主要用途是用作函数的形参。通过引用传递参数,函数会访问使用原始数据,而不是像按值传递一样使用副本。

    (1)创建引用变量

    int rats;
    int & rodents = rats;//rodents为rats的引用,即别名  这两个值表明的是同一个事物,同一块内存同一个地址同一个值

    特点:与const指针比较接近,必须在声明引用变量时进行初始化。一旦与某个变量关联,就将一直效忠与它。

    引用与变量一体,共用同一块内存,看好引用的内存和值即可。数组不能声明引用

    (2)将引用作为函数参数

    引用作为函数参数,原理是将函数中变量名成为调用程序中的变量的别名。

    按值传递
    void sneezy(int x);
    int main()
    {
        int times = 20;//创建times变量,并赋值20
      sneezy(times);
    }

    void sneezy(int x)//创建x变量,将传递来的值赋值给x
    {
      ...
    }
    2个变量,两个名字,x和times除了值相同,完全两个变量,没有任何联系
    按引用传递
    void grumpy(int &x);
    int main()
    {
        int times = 20;//创建times变量,赋值20

      grumpy(times); }

    void grumpy(int &x)//x为times的别名
    {...}
    times和x是同一个变量,只不过有两个名称

    函数调用使用实参初始化形参,因此函数的引用参数被初始化为函数调用传递的实参。

    (3)关于引用的临时变量和const引用

    如果实参和引用参数类型不匹配,C++将生成临时变量。仅当参数为const引用时,C++才允许这样使用不会报错。

    关于临时变量,如果引用参数时const,则下面两种情况下生成临时变量(匿名变量)

           实参的类型正确,但不是左值。

           实参的类型不正确,但可以转换为正确的类型

    double refcube(const double & ra)//仅当为常量引用,可以允许下面的情况,因为不修改ra的值,所以是不是临时变量无所谓
    {
        return ra * ra * ra;
    }
    
    int main()
    {
    
        double side = 3.0;
        double * pd = &side;
        double & rd = side;
        long edge = 5L;
        double lens[4] = {2.0, 5.0, 10.0, 12.0};
        refcube(side);
        refcube(lens[2]);
        refcube(*pd);
        refcube(edge);//生产临时变量
        refcube(7.0);//生产临时变量
        refcube(side+7.0);//生产临时变量
    
        const double & p12 = 0.1+0.2;
        system("pause");
        return 0;
    }

    为什么非const引用不可以这样操作?

    理解如下:

    void swapr(int &a, int &b)
    {
        int temp;
        temp = a;
       a = b;
    b = temp; }

    long a = 3, b = 5;
    swapr(a,b);

    上述实参类型和形参的引用类型不匹配,编译器会创建两个临时int变量,将其初始化为3和5,然后交换临时变量的值,实参的值不变

    一个接受引用参数的函数的目的就是修改实参的值,如果创建临时变量,就阻止了函数的这一作用。

    实际上,对于形参为const引用的C++函数,如果实参不匹配,则其行为类似于按值传递,为确保原始数据不被修改,将使用临时变量来存储值。

    将引用参数声明为常量数据的引用的理由:

    1)使用const可以避免无意中修改数据的编程错误

    2)使用const使函数能够处理const和非const实参,否则将只能接受非const数据

    3)使用const引用能使函数能够正确生成并使用临时变量

    (4)将引用用于结构

    引用非常适合用于结构和类,引用主要是为了用于这些类型,而不是基本的内置类型

    struct free_throws
    {
      std::string name;
      int made;
      int attempts;
      float percent;
    }
    free_throws dup;
    free_throws four = {"Whily Looper", 5, 9};
    free_throws five = {"Long Long", 5, 9};
    free_throws & accumulate(free_throws & target, const free_throws & source);
    accumulate(dup, five) = four;//不常用,作为一个例子解释下面问题

    1.函数形参为引用:与按值传递相比,引用传递少了复制拷贝原始结构这一步,可以节省时间和内存。

    2.函数返回值为引用:传统返回机制会计算return后变量(这个值被复制到一个临时位置),并将结果返回给调用函数,

    例:dup = accumulate(four, five);

    如果accumulate返回一个结构,不是引用,会将整个结构复制到一个临时位置,再将这个拷贝复制给dup

    现在是引用,会直接把函数中return的值复制给dup,效率更高

    4.返回引用时应注意:避免返回函数终止时不再存在的内存单元引用。1)返回一个作为参数传递给函数的引用  2)用new来分配新的存储空间,返回指向该空间的指针

    5.可以将const用于引用返回类型,避免返回值被改变

    accumulate(dup, five) = four;可以通过编译,但是若此函数返回值为结构体,则不能通过编译
    原因:
    在赋值语句中,左边必须是可以修改的左值,即左边的子表达式必须标识一个可修改的内存块,此函数返回值为结构体引用时,函数返回dup的引用,它确实标识的时一个这样的内存块,所以
    可以编译通过
    常规(非引用)返回类型是右值---不能通过地址访问的值,这种表达式可以出现在赋值语句的右边,但是不能出现在左边。其他右值包括字面值如10.0和表达式如x+y。获取字面值的地址
    没有意义,但是为何常规函数返回值是右值呢,因为这种返回值位于临时内存单元中,运行到下一条语句时,它们可能就不在存在了。

    (5)将引用用于类对象

    类中有一个特征,基类引用可以指向派生类对象,无需进行强制类型转换。

    可以定义一个接受基类引用作为参数的函数,调用该函数时,可以将基类对象作用参数,也可以将派生类对象作为参数。

      

  • 相关阅读:
    关于32位操作系统和64位操作系统对InstallShield打包的影响
    NEWS: Symantec宣布Wise Package Studio将终止
    InstallShield 2012新功能试用(2) 调用MsiGetProperty等MSI API发生变化
    Basic INFO 在命令行Build InstallShield安装包工程获得压缩安装包
    NEWS InstallShield 2012 Service Pack 1发布
    Basic INFO InstallShield Basic MSI工程中如何在SetupCompleteSuccess界面中启动Readme
    Basic INFO InstallShield的脚本编辑器中如何显示代码行号
    Basic INFO 关于在InstallShield制作的安装包界面中删除InstallShield文字的厂商回复
    Basic INFO InstallShield工程中如何让产品的快捷方式名称始终与产品名保持一致
    Basic INFO: 创建隐藏文件夹
  • 原文地址:https://www.cnblogs.com/deerfig/p/11906916.html
Copyright © 2011-2022 走看看