为何C++拷贝构造函数参数必须为引用形式
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了为何C++拷贝构造函数参数必须为引用形式,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3998字,纯文字阅读大概需要6分钟。
内容图文
![为何C++拷贝构造函数参数必须为引用形式](/upload/InfoBanner/zyjiaocheng/612/69e27ff9000e480cb6259d5fcb042552.jpg)
文章目录
1. 参数传递
?? ??在C++中,有三种方法可将数据传递给函数,分别是:引用、传值和指针(C风格),它们在效率、存储以及性能方面都有着不同的特点。对于引用,本质上就是指针,它只是作为指针的语法糖(“语法糖”一词,来自阅读 前桥和弥《征服C指针》一书)。因此着重分析传值和引用两者的区别。
1.1 传值
?? ??对于传值方式,当对象或内置类型(eg:int、double、float等)数据传递给函数时候,函数将会为每个实参(即待传给函数的参数)做一份拷贝操作,这也就是通常所说的“副本”,这样一来,就需要分配额外的内存空间,所有值和子对象都被分别复制和存储。对于对象类型,会调用拷贝构造函数拷贝一份数据,而内置类型,其拷贝成本相对较低、通常也不会带来其他性能的影响。然而,若传递给函数的数据是一个大的值(比如vector、list或结构体数组等),那么这个复制过程对于CPU、内存和存储方面都有较大的速度影响及性能损失。
?? ?? 比如,一个vector中拥有一万个字符串变量,若以传值方式给fun函数,绝对不是明智的选择。
void fun(vector<string> v1/*v1.size() = 10000*/){}
1.2 引用方式
?? ??当对象或内置类型以引用方式将数据传递给函数时,将不会产生数据拷贝的动作,因为函数被赋予的是数据本身的内存地址。没有拷贝操作,也就意味着不需要额外申请内存地址、存储空间和CPU。这极大的提高了CPU的处理速度和性能。
2. 初始化方式
?? ?? C++有几种不同的初始化方式。若使用等号(“=”)来初始化一个变量,则执行的是拷贝初始化(Copy Initializition),编译器把等号右侧的值拷贝到新创建的对象中去。若不使用等号,则执行的是直接初始化(Direct Initialization)。
string s1 = "hello world."; //拷贝初始化
string s2("good"); //直接初始化
string s3(5, 'h'); //直接初始化
?? ??通常情况下,当初始化值仅有一个时候,使用拷贝初始化或是直接初始化均可(比如上面示例中的s1、s2)。但是若初始化的值有多个(比如s3),往往直接使用直接初始化。当然也可以使用拷贝初始化方式,如:
string s1 = string(5, 'h');
?? ?? 它等价于:
string s1;
string s2(5, 'h');
s1 = s2;
或是
string s2(5, 'h');
string s1 = s2;
2.1 拷贝构造函数
?? ?? 在了解C++变量初始化方式及参数传递形式之后,进入本文主题“拷贝构造函数”。《C++ Primer》13.1.1中描述到,“如果一个构造函数的第一个参数是自身类型的引用,且任何额外参数都有默认值,则该构造函数是拷贝构造函数。” 如下面代码中注释处的函数为拷贝构造函数。
class TCopy
{
TCopy(const Tcopy &t){} //拷贝构造函数
};
?? ??现在有两个疑问:
?? ??(1) 拷贝构造函数参数一定需要以const形式么?
?? ??(2) 拷贝构造函数参数可不可以用传值方式?
?? ??我们先来看第一个问题,当拷贝构造函数的参数以非const的引用形式时,是否能够正常工作。示例代码如下:
class TCopy
{
public:
TCopy(int a)
:m_a(a){}
TCopy(TCopy &t){}
void Display(){
cout << "m_a: "<<m_a<<endl;
}
private:
int m_a;
};
int main()
{
TCopy t(1); //构造函数-直接初始化
TCopy t1 = t; //拷贝构造函数初始化
t.Display(); //打印结果: m_a: 1
return 0;
}
?? ???? ???? ???? ???? ??demo打印结果
?? ??通过打印结果可看到,不加const修饰的引用是可以的。对于拷贝构造函数中的const引用,主要有两处作用(强烈建议都加上)。首先,避免被调函数内部意外修改实参的值;其次,避免用户将临时对象绑定到非const引用上。如下示例:
class TCopy
{
public:
TCopy(){}
TCopy(TCopy &t){}
};
TCopy Test()
{
TCopy t;
return t;
}
int main()
{
TCopy t;
TCopy t1 = Test();
return 0;
}
?? ??编译器将错误提示:
D:\code\01_09\main.cpp:25: error: no matching function for call to 'TCopy::TCopy(TCopy)'
TCopy t1 = Test();
^
D:\code\01_09\main.cpp:12: note: no known conversion for argument 1 from 'TCopy' to 'TCopy&'
?? ?? 现在来看第二个问题,以普通传值方式,将数据传递给函数是否可以的问题。
class TCopy
{
public:
TCopy(){}
TCopy(TCopy t){}
};
?? ?? 直接编译报错:
D:\code\1\main.cpp:12: error: invalid constructor; you probably meant 'TCopy (const TCopy&)'
TCopy(TCopy t){}
^
?? ??当主调函数中把数据传递给被调函数形参时候,若以值形式传递,则相当于:
?? ???? ?? ?? ?? 数据类型 a = b ;
?? ??此处b为实参, a为形参。当调用拷贝构造函数时候,必须将同类型的对象传递给它,而这里是传值形式,所以传递的对象需要在参数中进行拷贝,拷贝构造函数将一个对象的值一一拷贝到另外一个对象中。然而这里仅给出了拷贝构造函数的定义,所以该拷贝构造函数将被递归调用,直到编译器请求内存空间不足为止。这也就是为何拷贝构造函数必须要以引用的形式的根本原因。
内容总结
以上是互联网集市为您收集整理的为何C++拷贝构造函数参数必须为引用形式全部内容,希望文章能够帮你解决为何C++拷贝构造函数参数必须为引用形式所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。