c++ - C++ Primer 第 5 版中发现的错误(复制初始化与直接初始化)
问题描述
嗨,我正在尝试了解复制构造函数的工作原理并查看示例。示例如下:
{//new scope
Sales_data *p = new Sales_data;
auto p2 = make_shared<Saled_data>();
Sales_data item(*p); // copy constructor copies *p into item
vector<Sales_data> vec;
vec.push_back(*p2);// copies the object to which p2 points
delete p;
}
我的问题是:
- 为什么写“复制构造函数将 *p 复制到
item
”?我的意思是,item
是直接初始化的。如果我们会写,Sales_data item = *p;
那么它将被称为复制初始化,所以他们为什么要写复制构造函数将 *p 复制到注释中的项目中。
现在,为了自己验证这一点,我尝试自己创建一个简单的示例,但我也无法正确理解这个概念。我的自定义示例如下:
#include<iostream>
#include<string>
class MAINCLASS{
private:
std::string name;
int age =0;
public:
MAINCLASS(){
std::cout<<"This is default initialization"<<std::endl;
}
MAINCLASS(MAINCLASS &obj){
std::cout<<"This is direct initialization"<<std::endl;
}
MAINCLASS(const MAINCLASS &obj):name(obj.name),age(obj.age){
std::cout<<"This is copy initialization"<<std::endl;
}
};
int main(){
MAINCLASS objectone;
MAINCLASS objecttwo =objectone;
MAINCLASS objectthree(objectone);
return 0;
}
现在当我运行这个程序时,我得到以下输出:
这是默认初始化
这是直接初始化
这是直接初始化
我对这个程序的问题如下:
- 为什么在我写的第二种情况下我们没有得到输出“这是复制初始化”
MAINCLASS objecttwo =objectone;
?我已经读过,在直接初始化函数匹配中使用了复制构造函数,我们将右手操作数成员复制到左手操作数成员中。所以当我写MAINCLASS objecttwo =objectone;
它应该调用复制构造函数并在屏幕上打印“这是复制初始化”。但相反,它是直接初始化对象。这里发生了什么?
解决方案
不要混淆复制构造和复制初始化。您可以使用直接或复制初始化复制构造。
复制初始化是指一组初始化语法和语义。这包括T a = b
语法。
复制构造函数是一种特殊的类方法,它接受所述类的参数。这个方法应该只接受一个参数(两者都做T&
或const T&
将做)。调用该函数时会发生复制构造。
考虑到这一点,我们可以继续回答您的问题。
- 为什么写“复制构造函数将 *p 复制到
item
”?我的意思是,item
是直接初始化的。如果我们会写,Sales_data item = *p;
那么它将被称为复制初始化......
两者都Sales_data item = *p
调用Sales_data item(*p)
复制构造函数。但是,前者使用复制初始化(T a = b
),而后者使用直接初始化(T a(b)
)。
- 为什么在我写的第二种情况下我们没有得到输出“这是复制初始化”
MAINCLASS objecttwo =objectone;
?
实际上,这里的问题不在于它是否是复制/直接初始化的。这是左值/右值重载解析的问题。
考虑以下程序:
#include <iostream>
void f(int& i) { std::cout << "int&\n"; }
void f(const int& i) { std::cout << "const int&\n"; }
int main() {
f(1); // f(const int&)
int i = 2;
f(i); // f(int&)
}
f
根据传递的值是左值还是右值来选择。在第一种情况下,1
是一个右值,因此f(const int&)
被称为(参见this)。在第二种情况下,i
是一个左值,f(int&)
选择它是因为它更通用。
因此,在您的情况下,两者都MAINCLASS objecttwo =objectone;
调用MAINCLASS objectthree(objectone);
复制构造函数。同样,前者使用复制初始化,而后者使用直接初始化。只是这两个调用都选择了非常量 ref 重载:MAINCLASS(MAINCLASS&)
.
推荐阅读
- binding - 使用 Aurelia Property Observer 忽略您自己的更改的最佳方法
- node.js - NPM 全局安装
- json - 使用 Swift JSON 从 TheMovieDB API 获取数据时遇到问题
- keycloak - Keycloak的请求错误中未提供客户端密码
- macos - Apple TextEdit,它的工具栏从何而来?
- angular - 无法使用 ng bootstrap modal 使用 angular 4 获取多参数值
- haskell - 是否可以在 Haskell 中具有具有多个类型签名的函数
- php - 根据持续时间以百分比计算 div 宽度
- ruby-on-rails - Rails activeadmin 导出 PDF
- git - 当我克隆按钮单击时括号 Git 错误