• 引用&&指针&&返回值&&定义声明&&生命周期&&const


    1. 首先了解一下声明和定义的区别:

        声明,其实就是描述一个元素是有什么构成的;
        定义,其实就是在内存中划分出一个区域且用符号关联起来;
        变量和对象不加extern永远是定义,类中的除外。 函数只有函数头是声明,有函数体的是定义。 类永远只是声明。类成员函数的函数体是定义
        函数的声明和定义的不同点在于函数的声明不包含函数体,仅仅是fact();

    2. 其次了解一下局部对象的生命周期

        局部变量
    i.    形参和函数体内定义的变量统称局部变量
    ii.    局部变量转换成为全局变量,则使用static关键字就能实现;
    iii.    局部变量的生存周期,在函数调用时被创建,在函数结束的时候就销毁,例:形参
    iv.    有两种方式可以将函数体内值得改变传回主函数,一种是将形参设置为引用的形参,其实是实参和形参绑定在一块儿,因而值可以回传,另外一种是通过指针形参,改变实参传递过来地址的值,去改变函数体内的值。

    3. 引用

    A.    可能出现的错误情况:
    Int  ival =1024;
    Int  &refVal;  //引用必须进行初始化,
    改正: int &refVal = ival;
    //因为无法令引用重新绑定到另外一个对象,因此引用必须进行初始化;
    引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字;
    B.    情况2:
    Int  &refVal1 =10; // 错误:引用类型的初始值必须是一个对象,不能是字面值;
    double dval = 3.14;
    int &refVal =dval; //错误,此处引用类型的初始值必须是int类型的对象;
    C.    总结: 引用初始值必须是一个对象,不能是字面值;引用必须进行初始化;引用类型和绑定的类型必须一致。切记,哪怕类型之间可以相互转换,也不可以,必须类型一致;

    4. const &

    A.    const 用法
    i.    定义一种变量,它的值不能被改变。
    ii.    好处:用一个变量来表示缓冲区的大小,使用变量的好处是当我们觉得缓冲区大小不再合适时,很容易对其进行调整,但是我们又要随时警惕防止程序一不小心改变这个值。因而用const
    iii.    const 必须进行初始化;
    iv.    引用的好处:避免拷贝,可以直接比较;使用引用形参返回额外信息,主要是为了改善一个函数只能返回一个值得情况,这样函数可以返回多值。
    v.    补充:顶层const是指指针本身是个常量,指针所指的内容是可以改变的,当形参有顶层const时,顶层const可以忽略掉,传给他常量对象或者非常量对象都是可以的,因为传入形参的本身就是局部变量,不会改变实参的值。
    vi.    数组引用形参
    B.    总结:
    常量引用也必须进行初始化,并且不能通过该对象别名去修改已知非常量的值,绑定的值可以是常量也可以是非量,和引用有一点不同
    double dval = 3.14; const int &ri =dval;//当类型不同时,转换时可以进行的.
    //常量引用的好处之一避免拷贝对象~
    bool
    isShorter(const string &s1, const string &s2) { return s1.size() < s2.size(); }//避免拷贝对象

    //常量引用的好处之二___可以使函数返回多个值

    //返回s中c第一次出现的位置索引
    //引用形参occurs负责统计c出现的总次数
    
    string::size_type find_char(const string &s, char c, string::size_type &occurs)
    {
    auto ret = s.size(); //第一次出现的位置
    occurs = 0;
    for (decltype(ret) i = 0; i != s.size(); ++i)
    {
    if (s[i] == c)
    {
    if (ret == s.size())
    ret = i; //记录c第一次出现的位置
    ++occurs;//将出现的次数+1
    }
    }
    return ret; //出现次数通过occurs隐式传回
    }
    
    int main()
    {
    string s = { "Hello world, welcome to beijing !" };
    decltype(s.size()) ctr = 0;
    auto index = find_char(s, 'o', ctr);
    cout << "string S has " << ctr << " times o" << endl;
    }

    5. 返回值为&

    A.    关于返回值是如何返回的:返回的值用于初始化调用点的一个临时量,该临时两就是函数调用的结果。
    B.    不要返回局部对象的引用或指针,局部对象会在函数调用结束的时候释放内存;
    C.    引用返回的是左值;

    //返回值为常饮用出现的错误之一

    const string &manip()
    {
    string ret;//以某种方式改变一下ret
    if (!ret.empty())
    return ret; //错误:返回的是对局部变量的引用
    else
    return "Empty"; //错误:"Empty"是一个局部临时量
    }
    
    //  有的返回值也是局部变量,但是不会提示错误~~~
    
    1>e:c程序finalconstfinalconstfinalconst.cpp(10): warning C4172: 返回局部变量或临时变量的地址
    1>e:c程序finalconstfinalconstfinalconst.cpp(12): warning C4172: 返回局部变量或临时变量的地址

    6. 数组形参

    A.    数组的性质:不允许拷贝数组,使用数组时通常会将其转换成指针;
    因而函数传递数组时,实际上传递的是指向数组首元素的指针。
    B.    首先需要看一下三种等价的形参是数组的形式
    void  print(const int*);
    void print (const int[]);//可以看出来,函数的意图是作用于一个数组
    //因而 void print(const int *arr[])==void print (const int **arr)
    void print (const int[10]); //这里的维度表示我们期望数组含有多少元素实际不一定
    这里每个函数的唯一形参都是const int * 类型,这是一个底端const

    exe1:当形参为内置类型,不是混合类型(如指针、引用)

    void reset(int ival)
    {
    ival = 3;
    cout << ival << endl;
    }
    int main()
    {
    int ival1 = 5;
    reset(ival1);
    cout << ival1 << endl;
    }
    
    //输出值为3,5

    exe2:当形参为指针类型的时候

    void reset(int *ival)
    {
    *ival = 3;
    cout << *ival <<" "<< ival << endl;//当传递的值为指针的时候,可以在函数体内
    
    //通过指针改变指对象的值,并且该值被传回主函数,间接地改变主函数中所指地址中的值;
    
    int ival2 = 4;
    ival = &ival2;//改变函数传入的实参的值,也就是改变传入地址的值,仅仅是局部变量的拷贝,
    
    //并不能使实参的值改变,如果注释掉*ival = 3;该函数调用不会改变主函数的任意值
    
    }
    int main()
    {
    int ival1 = 5;
    reset(&ival1);
    cout << ival1 <<" "<<&ival1<< endl;
    }
    
    输出值为:3,002AFB04
    
            3,002AFB04

    exe:当形参为引用类型的时候

    void reset(int &ival)
    {
    ival = 3;
    cout << ival << " " << &ival<< endl;
    }
    int main()
    {
    int ival1 = 5;
    reset(ival1);
    cout << ival1 << " " << &ival1 << endl;
    }
    
    输出值为:3,002AFB48
    
             3,002AFB48

    exe:当形参为内置类型时,在函数体内定义的变量是局部变量,但是仍然可以将值赋给主函数中的某个变量~~,这是值传递~~

    int fact(int val)
    {
    int ret = 1;
    while (val > 1)
    ret *= val--;
    return ret;
    }
    
    int main()
    {
    int j = fact(5);
    cout << "5! is " << j << endl;
    return 0;
    }

    exe:当形参是未知个数,但是类型相同的时候,可以用类initializer_list

    void error_msg(initializer_list<string> i1)
    {
    for (auto beg = i1.begin(); beg != i1.end(); ++beg)
    cout << *beg << " ";
    cout << endl;
    }
    int main()
    { 
    string expected;
    string actual;
    if (expected != actual)
    error_msg({ "functional", expected, actual });
    else
    error_msg({ "functional", "okay" });
    return 0;
    }

    最后当指针出现的各种情况的总结:

     1 #include <iostream>
     2 #include <string>
     3 #include<vector>
     4 using namespace std;
     5 
     6 
     7 int g_val = 8;
     8 //数组的数组
     9 void  pointer(int *ival)
    10 {
    11     *ival = 10;
    12     cout << *ival << " " << ival << endl;
    13     //在此处应该是把实参的值改为10,并且地址应该相同
    14 }
    15 void  pointer1(const int *ival)
    16 {
    17     cout << *(ival + 2) << endl;    
    18     //输入的是数组的首地址,该地址的值不能改变,但是指针能向下移动
    19 }
    20 void pointer2(int *arr[])
    21 {
    22     cout <<**arr<<" "<< *arr << " " << arr << endl;
    23 }
    24 void pointer3(int(*arr)[4])//等价于void pointer3(int(arr[])[4])
    25 {
    26     for (size_t i = 0; i < 4; i++)
    27     {
    28         cout << (*arr)[i] <<" "<<arr[i]<< endl;//对指针数组的使用~
    29     }
    30 }
    31 int *pointer4()//有意义的为int * const pointer4()
    32 {
    33     
    34     return &g_val;//可以在类的使用中返回该值的地址,可以用于修改该对象的值;
    35 }
    36  
    37 
    38 int main()
    39 {
    40     int val = 4;
    41     int val1[4] = { 0, 1, 2, 3 };
    42     int val2[2][4] = { 0, 1, 2, 3, 4, 5, 6, 7 };
    43     int *val3 = &val;
    44     //多维数组初始化-----
    45     //还可以初始化{{0,1,2},{3,4,5}}
    46 
    47     //test void  pointer(int *ival)
    48     pointer(&val);
    49     cout << val << " " << &val << endl;
    50     pointer(val1);
    51     cout << val1[0] << " " << val1 << endl;
    52     //test void  pointer1(const int *ival)
    53     pointer1(val1);
    54 
    55     //test void pointer2(int **arr)
    56     pointer2(&val3);
    57     //void pointer3(int(*arr)[4])
    58     pointer3((val2+1));
    59     //test int  *pointer4()
    60     int *val4=pointer4();
    61     cout << val4 << " " << *val4 << endl;
    62     *val4 = 90;
    63     cout << val4 << " " << *val4 << endl;
    64     return 0;
    65 }

    实验结果:

    参考:

      函数返回值是否使用引用类型的问题:理解引用、返回值
    1. http://blog.csdn.net/sxhelijian/article/details/7466540  

          理解一般指针类型

    1. http://www.cnblogs.com/dzry/archive/2011/05/12/2044835.html 
  • 相关阅读:
    WCF 发布在iis上
    记一次服务器迁移过程
    期末总结
    典型用户和用户场景
    软件工程第四次作业 结对编程 增量开发
    第三次作业 结对编程
    我对git认识
    浅谈对IT的认识!
    本地Git仓库和远程仓库的创建和关联及github上传(git push)时出现error: src refspec master does not match any解决办法
    CSS下拉菜单
  • 原文地址:https://www.cnblogs.com/lwflourish/p/4152758.html
Copyright © 2020-2023  润新知