gpt4 book ai didi

c++ - 为什么我们必须发送const “type ”引用,而不只是将类型名称发送给构造函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 08:14:27 24 4
gpt4 key购买 nike

我试图制作一个可以生成日期的简单程序(是的,这是一项家庭作业),并且像大多数普通人一样:我将Class属性设为私有(private),我尝试将与im相同的类型发送给构造函数,但是编译器不接受它,我进行了一些研究,我发现在这种情况下,人们慷慨地向那些对OOP不太了解的构造函数女巫发送了const“类型”引用
那么,为什么我们必须将const“类型”引用而不只是类型名称发送给构造函数? &请给我一些面向初学者的链接或网站
这是我的守则的安宁:

 class Date {  
int d ;
int m ;
int y ;
public :
Date();
Date(int , int , int);
Date(const Date &);// my question is : why do we have to write this instead of Date( Date )
};

PS:对不起,我的英语

最佳答案

解释一下我们的问题:

why do we have to write Date(const Date &) instead of Date(Date)?



我将其分为两部分,第一部分回答为什么复制构造函数需要为每个引用获取其参数,第二部分回答为什么这需要成为const引用。

拷贝构造函数需要按引用接受其参数的原因是,对于每个拷贝都接受参数的函数 void f(T arg),当您将其称为 f(obj)时, obj使用arg的拷贝构造函数将复制到 T中的。因此,如果要实现复制构造函数,则最好不要逐个复制参数,因为在调用它时会调用复制构造函数,从而导致无限递归。您可以轻松地自己尝试:
struct tester {
tester(tester) {std::cout << "inside of erroneous copy ctor\n";}
};

int main()
{
tester t1;
std::cout << "about to call erroneous copy ctor\n";
tester t2(t1);
std::cout << "done with call erroneous copy ctor\n";
return 0;
}

该程序应该只写一行,然后再破坏堆栈。
注意:正如Dennis在他的评论中指出的那样,实际上并不能保证该程序可以编译,因此,根据您的编译器,您可能实际上无法尝试它。

底线:复制构造函数应通过引用接受其参数 ,因为每个副本都需要复制构造函数。

剩下的问题是,为什么是const T&而不是T& ?实际上,有两个原因。
逻辑原因是,当您调用复制构造函数时,您并不希望复制的对象发生变化。在C++中,如果您想表达某些东西是不可变的,请使用const。这告诉用户他们可以安全地将其珍贵的对象传递给您的副本构造函数,因为除了从其读取之外,它不会对其进行任何操作。作为一个很好的副作用,如果您实现了复制构造函数并意外地尝试写入该对象,则编译器会向您抛出错误消息,使您想起对调用方的 promise 。
另一个原因是您不能将临时对象绑定(bind)到非const引用,只能将它们绑定(bind)到const引用。例如,一个临时对象是函数可能返回的内容:
struct tester {
tester(tester& rhs) {std::cout << "inside of erroneous copy ctor\n";}
};

tester void f()
{
tester t;
return t;
}

调用f()时,会在内部创建一个tester对象,然后将其副本返回给调用方,该调用方随后可以将其放入另一个副本中:
tester my_t = f(); // won't compile

问题是f()返回一个临时对象,并且为了调用复制构造函数,该临时对象将需要绑定(bind)到rhs的复制构造函数的tester参数,这是一个非const引用。但是您不能将临时对象绑定(bind)到非const引用,因此代码将无法编译。
虽然您可以根据需要解决此问题(只是不复制临时文件,而是将其绑定(bind)到const引用,这会将临时文件的生存期延长到引用生存期的末尾:const tester& my_t = f()),但人们希望能够复制您类型的临时人员。

底线:复制构造函数应通过 const引用接受其参数,因为否则用户可能不愿意或无法使用它。

这是另一个事实:在下一个C++标准中,您可以重载临时对象的函数,即所谓的 rvalues 。因此,您可以有一个特殊的复制构造函数,该构造函数接受使“正常”复制构造函数超载的临时对象。如果您的编译器已经支持此新功能,则可以尝试一下:
struct tester {
tester(const tester& rhs) { std::cout << "common copy ctor\n"; }
tester( tester&& rhs) { std::cout << "copy ctor for rvalues\n"; }
};

当您使用上述代码调用我们的f()
tester my_t = f();

当将对f()的调用返回的临时对象复制到my_t时,应该调用用于rvalues的新副本构造函数,并且可能会调用常规的复制构造函数,以便将t对象从f()内部复制到返回的临时对象。 (注意:您可能必须禁用编译器的优化才能看到此信息,因为允许编译器优化所有复制。)
那你能做什么呢?好吧,当您复制右值时,您知道从复制对象中调用复制构造函数后将销毁该对象,因此采用右值(T&&)的复制构造函数可能只是从参数中窃取值,而不是复制它们。由于该对象无论如何都将被销毁,因此没有人会注意到。
对于某些类(例如,对于字符串类),将值从一个对象移动到另一个对象可能比复制它们便宜得多。

关于c++ - 为什么我们必须发送const “type ”引用,而不只是将类型名称发送给构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2878972/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com