C++引用

一、引用

1.创建引用变量

c和c++使用&符合来表示指示变量的地址,c++给&符合赋予了另一个含义,将其用来声明引用,例如:将rodents作为rats变量的别名:

int rats;
int & rodents = rats;
//&不是地址运算符,而是类型标识的一部分。
//就像声明中的`char*`指的是指向char的指针一样,`int&`指的是指向int的引用。

实例:

#include <iostream>
using namespace std;
int main()
{
    int rats=101;
    int & rodents=rats;
    cout<<"rats="<<rats;
    cout<<",rodents="<<rodents<<endl;
    rodents++;
    cout<<"rats="<<rats;
    cout<<",rodents="<<rodents<<endl;
    cout<<"rats address="<<&rats;
    cout<<",rodents adderss= "<<&rodents<<endl;
    return 0;
}

在这里插入图片描述
注:

  1. &运算符不是地址运算符,而是将rodents得类型声明为int&,即指向int的变量的引用。
  2. 声明引用时将其初始,而不能像指针那样,先声明后,再赋值。(重要)

2.将引用用作函数参数

  1. 引用经常被用作函数参数,使得函数中的变量名成为调用程序中的变量的别名。
  2. 这种传递参数的方法称为按引用传递。按引用传递允许被调用的函数能够访问调用函数中的变量。

实例:

#include <iostream>
using namespace std;
void swapr(int & a,int & b);
void swapp(int * p,int * q);
void swapv(int a,int b);
int main()
{
    int wallet1=300;
    int wallet2=350;
    cout<<"wallet1= $"<<wallet1;
    cout<<"wallet2= $"<<wallet2;

    cout<<"Using references to swap contents:"<<endl;
    swapr(wallet1,wallet2);
    cout<<"wallet1= $"<<wallet1;
    cout<<",wallet2= $"<<wallet2<<endl;

    cout<<"Using pointers to swap contents again:"<<endl;
    swapp(&wallet1,&wallet2);
    cout<<"wallet1= $"<<wallet1;
    cout<<",wallet2= $"<<wallet2<<endl;

    cout<<"Trying to use passing by value:"<<endl;
    swapv(wallet1,wallet2);
    cout<<"wallet1= $"<<wallet1;
    cout<<",wallet2= $"<<wallet2<<endl;
    return 0;

}
void swapr(int & a,int & b)//引用传递
{
    int temp;
    temp=a;
    a=b;
    b=temp;
}
void swapp(int * p,int * q)//指针传递
{
    int temp;
    temp=*p;
    *p=*q;
    *q=temp;
}
void swapv(int a,int b)//普通传递
{
    int temp;
    temp=a;
    a=b;
    b=temp;

}

在这里插入图片描述

3.引用作为函数的返回值

引用作为函数返回值时,不能返回局部数据(例如局部变量、局部对象、局部数组等)的引用。

#include <iostream>
using namespace std;
int &my_arr(void)
{
    int num=200;
    return num;//函数返回什么变量,引用就是该变量的别名
    //函数的返回值是引用时,不要返回局部变量
}
int &my_arr1(void)
{
    static int num=100;
    return num;
}
int main()
{
    int &pt=my_arr();
    //cout<<"pt="<<pt<<endl;非法访问
    int &pt1=my_arr1();
    cout<<"pt1="<<pt1<<endl;
}

在这里插入图片描述

当函数返回值作为左值 那么函数的返回值类型必须是引用。

#include <iostream>
using namespace std;
int& my_arr(void)
{
    static int num=100;
    cout<<"num="<<num<<endl;
    return num;
}
int main()
{
    //函数的返回值,作为左值
    my_arr()=5000;
    my_arr();
}

在这里插入图片描述

4.引用给数组取别名
//方法1:
#include <iostream>
using namespace std;
int main()
{
    int arr[5]={1,2,3,4,5};
    int (&my_arr)[5]=arr;

    int i=0;
    for(i=0;i<5;i++)
      cout<<my_arr[i]<<" "<<endl;
}

在这里插入图片描述

//方法2:和typedef一起使用

#include <iostream>
using namespace std;
int main()
{
    int arr[5]={1,2,3,4,5};
    typedef int Pn[5];//用typedef给数组arr取别名
    //Pn就是数组的类型(5个int元素);
    //my_arr数组的别名
    Pn &my_arr=arr;

    int i=0;
    for(i=0;i<5;i++)
        cout<<my_arr[i]<<" "<<endl;
}

在这里插入图片描述

5.常引用
#include <iostream>
using namespace std;
typedef struct
{
    int num;
    char name[32];
}STU;
void my_arr(STU tmp)//普通结构体变量作为形参,开销太大
{
    cout<<"学号:"<<tmp.num<<",姓名:"<<tmp.name<<endl;
}
void my_arr1(const STU &tmp)//tmp为常引用
{
    //tmp.num=2000;没有加const,num能修改值,加const不能
    cout<<"学号:"<<tmp.num<<",姓名:"<<tmp.name<<endl;
}
int main()
{
    STU pn={12,"Tom"};
    my_arr1(pn);//传引用不需要修改pn
}

在这里插入图片描述
常量引用:

  1. 常量引用的定义格式: const Type& ref = val;

  2. 常量引用注意: 字面量不能赋给引用,但是可以赋给 const 引用 const 修饰的引 用,不能修改。

实例:

#include <iostream>
using namespace std;
int main()
{
    //给常量10取个别名:pn
    //int &针对是int,10是const int类型
    //const int 针对的是const int,10是const int类型。
    const int & pn=20;
    cout<<"pn="<<pn<<endl;
}

在这里插入图片描述

6.将引用用于结构

使用结构引用参数的方式与使用基本变量引用相同。只需在声明结构参数时使用引用运算符&即可。如:

struct free_throws
{
	string name;
	int made;
	int attempts;
	float percent;
};

则可以这样编写函数原型,在函数中将指向该结构的引用作为参数:

void set_pc(free_throws & ft);
//防止函数修改传入的结构,可使用const :
void display(const free_throws & ft);

实例:

#include<iostream>
#include<string>
using namespace std;

struct free_throws {
    string name;
    int made;
    int attempts;
    float percent;
};

void set_pc(free_throws& ft);
void display(const free_throws& ft);
free_throws& accumulate(free_throws& target, const free_throws& source);


int main() {
    free_throws one = { "Ifelsa Branch",13,14 };
    free_throws two = { "Andor Knott",10,16 };
    free_throws three = { "Minnie Max",7,9 };
    free_throws four= { "Whily Looper",5,9 };
    free_throws five= { "Long Long",6,14 };
    free_throws team = { "Throwgoods",0,0 };

    free_throws dup;

    set_pc(one);
   
    display(one);
    accumulate(team, one);
    display(accumulate(team, two));
    accumulate(accumulate(team, three), four);
    display(team);

    dup = accumulate(team, five);

    cout << "Displaying team:\n";
    display(team);
    cout << "Display dup after assignment:\n";
    display(dup);
    set_pc(four);


    accumulate(dup, five) = four;
    cout << "Displaying dup after ill-advised assignment:\n";
    display(dup);
    return 0;

}

void set_pc(free_throws& ft)
{
    if (ft.attempts != 0)
        ft.percent = 1000.0f * float(ft.made) / float(ft.attempts);
    else
        ft.percent = 0;
}
 
 //此函数形式结构的内容,而不修改它,因此使用了一个const引用参数,也可以按值传递结构,但与复制原始结构的拷贝相比,使用引用节省时间与内存。
void display(const free_throws& ft)
{
    cout << "Name:" << ft.name << endl;
    cout << "Made:" << ft.made << endl;
    cout << "Attempts:" << ft.attempts << endl;
    cout << "Percent:" << ft.percent << endl;
}


free_throws& accumulate(free_throws& target, const free_throws& source)
{
    target.attempts += source.attempts;
    target.made += source.made;
    set_pc(target);
    return target;
}

在这里插入图片描述

set_pc(one);
  1. 函数set_pc()的形参ft为引用,因此ft执行one,函数set_pc的代码设置成员one.percent

  2. 这里按值传递不行,因此将导致设置的是one的临时拷贝的成员percent。

  3. 另一种方法:使用指针参数并传递地址:

set_pc(&one);
...
void set_pc(free_throws * pt)
{
if(pt->attempts !=0)
pt->percent = 100.0f*float(pt->made)/float(pt->attempts);
else
pt->percent = 0;
}
accumulate(team,one);

此函数接受两个结构参数,并将第二个结构的成员attempts和made的数据加到第一个结构相应成员中。只修改了第一个结构,因此第一个参数为引用,而第二个参数为const引用:

free_throws & accumulate(free_throws & target,const free_throws & source);

返回值呢?可以将返回值声明为void,但有函数调用:

display(accumulate(team,two));
//此函数将结果对象team作为第一个参数传递给accumulate()。意味着在函数accumulate()中,target指向的是team。
//函数accumulate()修改team,再返回指向它的引用。

注意返回语句:

return target;

如果返回类型被声明为free_throws而不是free_throws &,上述语句将返回target(也就是team)的拷贝,但返回类型为引用,意味着返回的是最初传递给accumulate()的team()对象。

accumulate()的返回值作为参数传递给了display(),这意味着将team传递给了display()。 display()的参数为引用,这意味着函数display()中的ft指向的是team,因此将显示team的内容。所以,下述代码:

display(accumulate(team,two));
//与下面代码等效:
accumulate(team,two);
display(team);

上述逻辑也适用于下面语句:

accumulate(accumulate(team,three),four);
//该语句与下面等效:
accumulate(team,three);
accumulate(team,four);

下面是赋值语句:

dup = accumulate(team,five);//将team中的值赋值到dup中。
accumulate(dup,five) = four;
//将值赋值给函数调用,可行的,因为函数的返回值是一个引用。
//若函数`accumulate()`按值返回,这条语句不能通过。由于返回的是指向dup的引用,上述代码于下面等效:
accumulate(dup,five);
dup = four;
//其中第二条语句消除了第一条所做的工作,因此在原始赋值语句使用accumulate()的方式并不好。

7. 为何要返回引用

传统返回机制与按值传递函数参数类似:计算关键字return后面的表达式,并将结果返回给调用函数。从概念上说,这个值被复制到一 个临时位置,而调用程序将使用这个值。请看下面的代码:

double m = sqrt(16.0);//值 4.0 被复制到一 个临时位置,然后被复制给 m 。
cout<<sqrt(25.0);//值 5.0 被复制到一 个临时位置,然后被传递给 cout 
//实际上,编译器可能合并某些步骤。
dup = accumulate(team,five);
//若accumulate()返回一 个结构,而不是指向结构的引用,将把整个结构复制到一 个临时位置,再将这个拷贝复制给dup。
//但在返回值为引用时,将直接把team复制到dup, 其效率更高。

注:返回应用的函数实际上是被引用的变量的别名。

8.返回引用时注意的问题

返回引用最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。应避免编写下面的代码:

const free_throws & clone2(free_throws & ft){
free_throws newguy;//错误的第一步
newguy = ft;//复制信息
return newguy;//返回对副本的引用
}
  1. 该函数返回一 个指向临时变量 (newguy) 的引用,函数运行完毕后它将不再存在。同样,也应避免返回指向临时变量的指针。

  2. 为避免这种问题,最简单的方法是,返回一 个作为参数传递给函数的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用也将指向这些数据。accumulate()正是这样做的。

  3. 另一 种方法是用 new 来分配新的存储空间。前面见过这样的函数,它使用 new 为字符串分配内存空间,并返回指向该内存空间的指针。下面是使用引用来完成类似工作的方法:

const free_thorws & clone(free_throws & ft)
{
free_throws * pt;
*pt = ft;
return *pt;
}

第一 条语句创建一 个无名的 free_throws结构,并让指针pt指向该结构,因此*pt就是该结构。上述代码似乎会返回该结构,但函数声明表明,该函数实际上将返回这个结构的引用。这样,便可以这样使用该函数:

free_throws & jolly = clone(three);

这使得jolly成为新结构的引用,这种方法存在一个问题:

  1. 在不再new分配的内存时,应使用delete来释放它们。

  2. 调用clone()隐藏了对new的调用,这使得以后很容易忘记使用delete来释放内存。

  3. 后面讨论的auto_ptr模板以及C++11新增的unique_ptr可帮助程序员自动完成释放工作。

9.为何将const用于引用返回类型

例:

accumulate(dup,five) = four;
  1. 首先将five的数据添加到dup中,再使用four的内容覆盖dup的内容。这条语句为何能够通过编译呢?在赋值语句中,左边必须是可修改的左值。

  2. 在赋值表达式中,左边的子表达式必须标识一 个可修改的内存块。在这里,函数返回指向dup 的引用,它确实标识的是一 个这样的内存块,因此这条语句是合法的。

  3. 另一 方面,常规 (非引用)返回类型是右值:不能通过地址访问的值。这种表达式可出现在赋值语句的右边,但不能出现在左边。

  4. 其他右值包括字面值(如10.0)和表达式(如 x+ y)。显然,获取字面值(如10.0)的地址没有意义,但为何常规函数返回值是右值呢?这是因为这种返回值位于临时内存单元中,运行到下 一 条语句时,它们可能不再存在。

假设您要使用引用返回值,但又不允许执行像给accumulate()赋值这样的操作,只需将返回类型声明为const引用:

const free_throws & accumulate(free_throws & target,const free_throws & source);

现在返回类型为const, 是不可修改的左值,因此下面的赋值语句不合法:

accumulate(dup,five) = four;//不允许const引用返回

该程序中的其他函数调用又如何呢?返回类型为const引用后,下面的语句仍合法:

display(accumulate(team, two)) ; 

这是因为display()的形参也是const free_throws& 类型。下面的语句不合法,因此accumulate()的第一个形参不是const:

ccumulate(accumulate(team, three), four); 

这影响大吗?就这里而言不大,因为仍可以这样做:

accumulate(team, three); 
accumulate(team, four); 
  1. 仍可以在赋值语句右边使用accumulate()。
  2. 通过省略const, 可以编写更简短代码,但其含义也更模糊。
  3. 常,应避免在设计中添加模糊的特性,因为模糊特性增加了犯错的机会。将返回类型声明为const引用,
10.将引用用于类对象

将类对象传递给函数时,c++通常的做法是使用引用。让string ostream istream ofstream 和ifstream等类的对象作为参数,例使用string类:

#include <iostream>
#include<string>
using namespace std;
string version1(const string &s1,const string & s2);
const string & version2(string & s1,const string & s2);
const string & version3(string & s1,const string & s2);
int main()
{
    string input;
    string copy;
    string result;
    cout<<"Enter a string:";
    getline(cin,input);
    copy=input;
    cout<<"Your string as entered: "<<input<<endl;
    result=version1(input,"***");
    cout<<"Your string enhanced :"<<result<<endl;
    cout<<"Your original string:"<<input<<endl;

    result=version2(input,"###");
    cout<<"Your string enhanced:"<<result<<endl;
    cout<<"Your original string:"<<input<<endl;

    cout<<"Resetting original string"<<endl;
    input=copy;
    result=version3(input,"@@@");
    cout<<"Your string enhanced:"<<result<<endl;
    cout<<"Your original string:"<<input<<endl;
    return 0;
}
string version1(const string &s1, const string &s2)
{
    string temp;
    temp=s2+s1+s2;
    return temp;
}
const string & version2(string &s1, const string &s2)
{
    s1=s2+s1+s2;
    return s1;
}
const string & version3(string &s1, const string &s2)
{
    string temp;
    temp=s2+s1+s2;//相加得到新字符串
    return temp;
}

在这里插入图片描述

11.引用的属性和特别之处

使用引用参数时,需要了解些特点。例:使用两个函数计算参数的立方,其中一个函数接受double类型的参数,另一个接受double引用。

#include<iostream>
#include<climits>
using namespace std;
double cube(double a);
double refcube(double &ra);
int main()
{
    double x =3.0;
    cout<<cube(x);
    cout<<"=cube of "<<x<<endl;
    cout<<refcube(x);
    cout<<"= cube of "<<x<<endl;
    return 0;
}

double cube(double a)
{
    a*=a *a;
    return a;
}

double refcube(double &ra)
{
    ra *=ra * ra;
    return ra;
}

在这里插入图片描述

  1. refcube()函数修改了main()中的x值,而cube()没有,表明为何通常按值传递。
  2. 变量a位于cube()中,它被初始化为x的值,但修改了a并不会影响x。但由于refcube()使用引用参数,因此修改了ra实际上就是修改x。
  3. 如果想让函数使用传递给它的信息,而不对这些信息进行修改,同时又想使用引用,则应使用常量引用。例:在这个例子中,应在函数原型和函数头中使用const:double refacube (const double &ra);
  4. 如果使用基本数值类型,应采用按值传递的方式,而不用按引用传递的方式。数据大时,引用参数将很有用。

按值传递可使用多种类型的实参。例如:

double z = cube(x+2.0);//传递值
z=cube(8.0);
int k = 10;
z=cube(k);//k转换为double,传值
double yo[3] ={2.2,3.3,4.4};
z=cube(yo[2]);//传递值4.4

如果传递给接受引用参数的函数,将会更严格。例:如果ra是个变量的别名,则实参应是变量。下面代码不合理,因为表达式x+3.0并不是变量:

double z = refcube(x+3.0);

如果试图使用refcube(x+3.0)函数调用,将发出警告。
例如:不能将值赋给该表达式:

x+3.0 = 5.0;//无意义
12.对象、继承和引用
  1. ostream和ofstream类凸显了引用的一个有趣属性,正如前面介绍的ofstream对象可以使用ostream类的方法,这使得文件输入/输出的格式与控制台输入/输出相同。

  2. 使得能够将特性从一 个类传递给另一 个类的语言特性被称为继承,这将在后面详细讨论。简单地说,ostream是基类(因为ofstream是建立在它的基础之上的),而ofstream是派生类(因为它是从ostream派生而来的)。

  3. 派生类继承了基类的方法,这意味着ofstream对象可以使用基类的特性,如格式化方法precision()和setf()

  4. 继承的另 一 个特征是,基类引用可以指向派生类对象,而无需进行强制类型转换。这种特征的一 个实际结果是,可以定义 一 个接受基类引用作为参数的函数,调用该函数时,可以将基类对象作为参数,也可以将派生类对象作为参数。

  5. 例如,参数类型为ostream&的函数可以接受ostream对象(如cout)或您声明的 ofstream 对象作为参数。

下面程序通过调用同一 个函数 (只有函数调用参数不同)将数据写入文件和显示到屏幕上来说明了这一 点。该程序要求用户输入望远镜物镜和一 些目镜的焦距,然后计算并显示每个 目镜的放大倍数。放大倍数等于物镜的焦距除以目镜的焦距,因此计算很简单,该程序还使用一些格式化方法,这些方法用于cout和ofstream对象(在这个例子中是fout)时作用相同。

 #include<iostream>
    #include<fstream>
    #include<cstdlib>
    using namespace std;

void file_it(ostream & os, double fo, const double fe[] , int n);
const int LIMIT= 5;
int main()
{
    ofstream fout;
    const char * fn = "ep-data.txt";
    fout.open(fn) ;
    if(!fout.is_open())
    {
    cout<<"Can't open"<<fn<<".Byb.\n";
    exit(EXIT_FAILURE);

    double objective;
    cout<<"Enter the focal length of you telescope objective in mm:";
    cin>>objective;
    double eps[LIMIT];
    cout<<"Enter the focal lengths,in mm,of"<<LIMIT<<"eyepieces:\n";

    for(int i=0;i<LIMIT;i++)
    {
    cout<<"Eyepiece#"<<i+1<<": ";
    cin>>eps[i];
    }

    file_it(fout,objective,eps,LIMIT);//目镜数据写入ep_data.txt;fout的设置被修改,然后被恢复
    file_it(cout,objective,eps,LIMIT);//将同样信息以同样地格式显示到屏幕上;cout的设置被修改,然后被恢复
    cout<<"Done\n";
    return 0;
    }
}


 void file_it(ostream & os,double fo,const double fe[],int n)
 {


    ios_base::fmtflags initial;//存储这种信息所需的数据类型名称
    initial= os.setf(ios_base::fixed); //保存参数格式化状态;将对象置于使用定点表示的模式
    os.precision(0);
    os << "Focal length of objective: 11" << fo << "11 mm\n";
    os.setf(ios::showpoint);//将对象显示为小数点的模式即使小数部分为0
    os.precision(1);//显示多少位小数
    os.width(12) ;
    os<< "nf.1. eyepiece" ;
    os.width(15);
    os<<"magnification"<<endl;
    for(int i =0;i<n;i++)
    {
    os.width(12);
    os << fe[i] ;
    os. width(15) ;
    os << int(fo/fe[i] + 0.5) << endl;
    }
    os.setf(initial);//恢复初始格式化状态
}

运行:
在这里插入图片描述

13.临时变量、引用参数和const

若实参于引用参数不匹配,c++将生成临时变量。当前仅当参数为const引用时,C++才允许这样做,但以前不是,什么时候,c++生成临时变量,以及为何对const引用的限制是合理的。

首先,什么时候将创建临时变量?如果引用参数是const,则编译器将在下面两种情况下生成临时变量:

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

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

左值是什么?左值参数是可被引用的数据对象,例如:变量、数组元素、结构成员、引用和解除引用的指针都是左值。

非左值包括字面常量(用引号括起的字符串除外,它们由其地址表示)和包含多项的表达式。

常规变量和const变量都可以视为左值,因为可通过地址访问它们,但常规变量属于可修改的左值,而cosnt变量属于不可修改的左值。

如:假设重新定义了refcube(),使其接受个常量引用参数:

double refcube(const double &ra)
{
	return ra*ra*ra;
}

考虑如下代码:

double side = 3.0;
double * pd = &side;
double & rd = side;
long edgs = 5L;
double lens[4] = {2.0,5.0,10.0,12.0};
double c1 = refcube(side);
double c2 = refcube(lens[2]);
double c3 = refcube(rd);
doubele c4 = refcube(*pd);
double c5 = refcube(edge);//ra临时变量
double c6 = refcube(7.0);//ra临时变量
double c7 = refcube(side + 10.0);//ra临时变量
  1. 参数side、lens[2]、rd和*pd都是有名称的、double类型的数据对象,因此可以创建引用,而不需临时变量。
  2. edge虽然是变量。类型不匹配,double引用不能指向long。
  3. 另一方面,参数7.0和side+10.0的类型都正确,但没有名称,在这时编译器生成临时匿名变量,并让ra指向它。这些临时变量只在函数调用期间存在,此后编译器可以随便删除。

对于常量引用,这种行为是可行的,其他情况却不行呢?
例:

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

如果在早期C++较宽松规则下,执行下面的操作会发生什么?

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

这里类型不匹配,因此编译器将创建两个临时int变量,将它们初始化为3和5,然后交换临时变量的内容,而a和b保持不变。

  1. 接受引用参数的函数的意图是修改作为传递的变量,则创建临时变量将阻止这种意图的实现。解决方法:禁止创建临时变量,现在的C++标准正是这样的(然而,在默认情况下,有些编译器将发出警告,而不是错误消息,因此看到有关临时变量的警告,不要忽略)。

  2. refcube()函数,该函数的目的只是使用传递的值,而不是修改它们,因此临时变量不会造成任何不利的影响,反而使函数在可处理的参数种类方面更通用。因此,如果声明将引用指定为const,C++将在必要时生成临时变量。

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

注:如果函数调用的参数不是左值或与相应的cosnt引用参数的类型不匹配,则C++将创建类型正确的匿名变量,将函数调用的参数的值传递给该匿名变量,并让参数来引用该变量。

14. 应尽可能使用cons

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

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

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

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

c++新增了另一种引用:右值引用。这种引用可指向右值,是使用&&声明的:

double && rref = sqrt(36.00);
double j = 15.0;
double && jref = 2.0 * j+18.5;
cout<<rref<<'\n';
cout<<jref<<'\n';

目的为了让库设计人员能够提供有些操作的更有效的实现。

15. 何时使用引用参数

使用引用参数的主要原因有两个:

  • 程序员能够修改调用函数中的数据对象。

    • 通过传递引用而不是整个数据对象,可以提高程序的运行速度。
    • 当数据对象较大时(如结构和类对象),第二个原因最重要。

    这些也是使用指针参数的原因。这是有道理的,因为引用参数实际上是基于指针的代码的另一 个接口。那么,什么时候应使用引用、什么时候应使用指针呢?什么时候应按值传递呢?下面是一 些指导原则:

对于使用传递的值而不是修改的函数:

  1. 如果数据对象很小,如内置数据类型或小型结构,则按值传递。

  2. 如果数据对象是数组,则使用指针,因为这是唯一 的选择,并将指针声明为指向const的指针。

  3. 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间。

  4. 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象参数的标准方式是按引用传递。

对于修改调函数中数据的函数:

  1. 如果数据对象是内置数据类型,则使用指针。如果看到诸如fixit (&x)这样的代码(其中x是int),则很明显,该函数将修改x。

  2. 如果数据对象是数组,则只能使用指针。

  3. 如果数据对象是结构,则使用引用或指针。

  4. 如果数据对象是类对象,则使用引用。

当然,这只是一 些指导原则,很可能有充分的理由做出其他的选择。例如,对于基本类型,cin 使用引用。因此可以使用cin>>n,而不是cin>>&n

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值