我试图制作一个简单的程序(是的,这是一个家庭作业),可以生成日期,像大多数普通人一样:我将我的类属性设为私有,我试图发送相同的类型,我正在工作的构造函数但编译器没有接受它,我做了一些研究,我发现在类似的情况下,人们慷慨地发送一个const"类型"引用构造器女巫对我来说意味着不太了解OOP
所以为什么我们必须发送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 )
};
Run Code Online (Sandbox Code Playgroud)
PS:对不起我的英语
用我们的问题来解释:
为什么我们要写
Date(const Date &)而不是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;
}
Run Code Online (Sandbox Code Playgroud)
该程序应该只写一行然后吹掉堆栈.
注意:正如Dennis在他的评论中指出的那样,实际上这个程序不能保证编译,所以,根据你的编译器,你可能真的无法尝试它.
底线:复制构造函数应该通过引用获取其参数,因为每个副本获取它将需要复制构造函数.
这就留下了为什么它const T&而不是简单的问题T&?事实上,有两个原因.
逻辑原因是,当您调用复制构造函数时,您不希望复制的对象发生更改.在C++中,如果你想表达某些东西是不可变的,你可以使用const.这告诉用户他们可以安全地将他们珍贵的对象传递给你的拷贝构造函数,因为除了从它读取之外它不会对它做任何事情.作为一个很好的副作用,如果您实现了复制构造函数并意外地尝试写入该对象,编译器会向您抛出一条错误消息,提醒您对调用者的承诺.
另一个原因是您无法将临时对象绑定到非const引用,您只能将它们绑定到const引用.例如,临时对象是函数可能返回的内容:
struct tester {
tester(tester& rhs) {std::cout << "inside of erroneous copy ctor\n";}
};
tester void f()
{
tester t;
return t;
}
Run Code Online (Sandbox Code Playgroud)
当f()被调用时,一个tester对象内部创建的,然后它的一个副本被返回给调用者,那么这可能把它变成另一个副本:
tester my_t = f(); // won't compile
Run Code Online (Sandbox Code Playgroud)
问题是f()返回一个临时对象,并且为了调用复制构造函数,这个临时对象需要绑定到's copy构造函数的rhs参数tester,这是一个非const引用.但是您无法将临时对象绑定到非const引用,因此代码将无法编译.
如果您愿意,可以解决这个问题(只是不要复制临时文件,而是将其绑定到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"; }
};
Run Code Online (Sandbox Code Playgroud)
当您使用上面的代码来调用我们的 f()
tester my_t = f();
Run Code Online (Sandbox Code Playgroud)
当由调用返回的临时对象为右值的新的拷贝构造函数应该被称为f()被复制到my_t与常规拷贝构造函数会被调用,以便将复制t的对象从内部f()到返回暂时的.(注意:您可能必须禁用编译器的优化才能看到这一点,因为允许编译器优化掉所有复制.)
那么你有什么用呢?好吧,当你复制一个右值时,你知道复制的对象在调用复制构造函数之后会被销毁,所以带有rvalue(T&&)的复制构造函数可能只是偷了参数中的值而不是复制它们.由于物体无论如何都要被摧毁,没有人会注意到.
对于某些类(例如,对于字符串类),将值从一个对象移动到另一个对象可能比复制它们便宜得多.