我正在经历 Thinking in C ++ ,并对C ++中构造函数的行为产生了一些困惑。这是我的示例代码:
#include<iostream>
using namespace std;
class base
{
public:
int a;
/*Ctor 1*/ base() { cout<<" default"<<endl; }
/*Ctor 2*/ base(int a){ cout<<" base::int "<<endl; }
/*Ctor 3*/ base(const base& b) { cout<<" base::cc "<<endl; }
/*Asgn 1*/ base operator=(base b){
cout<<" base::assignment - base"<<endl;
return b;
}
/*Asgn 2*/ /* base operator=(int b){
cout<<" base::assignment - int"<<endl;
return (base)b;
} */
};
int main()
{
base b;
int a = 10;
b = a;
system("PAUSE");
return 0;
}
输出:
有人可以解释一下输出吗? 我只想打电话给
我无法理解为什么我调用赋值运算符和复制构造函数的其他对象是“int”类型。如果我取消注释“Asgn 2”,我会打电话给它而不是Asgn 1这是可以理解的。
如果我正在调用复制构造函数(它总是以对象引用作为参数),那是因为编译器将int转换为基类型吗?
答案 0 :(得分:2)
输出
default
base::int
base::assignment - base
base::cc
如下:
base b;
这里创建一个b
- 这将使用默认构造函数
int a = 10;
b = a;
我们有一个赋值 - 唯一可用的赋值类型为base
- 所以编译器会抓住它的头并说出“#ha; ah-ha&#34;得到了一个构造函数的版本,可以从base
创建一个int
类型的对象。我们可以使用它。
所以你得到了输出
cout<<" base::int "<<endl;
现在编译器可以使用赋值运算符。该参数是base
类型的对象,但因为它是临时的,所以不需要调用(参见http://en.cppreference.com/w/cpp/language/copy_elision),赋值运算符然后输出
cout<<" base::assignment - base"<<endl;
但是赋值不返回值作为引用 - 因此需要将此返回值复制到b
- 从而调用复制构造函数。因此
cout<<" base::cc "<<endl;
答案 1 :(得分:1)
首先,base(int a)
是一个转换构造函数
需要一个参数
它不使用explicit
关键字
转换构造函数可用于隐式转换:
void foo(base b);
void bar() {
foo(3);
}
此处int
参数将使用转换构造函数隐式转换为base
类型。
因为通过值参数(通过引用传递的参数)被复制,复制构造函数被正式调用;但是在这里,副本的源是一个临时对象,使用int
构造函数隐式创建的对象。因此,允许编译器融合临时和参数,直接构造目标对象。此优化是可选的,编译器仍必须验证是否可以调用复制构造函数:它在此处被声明和访问(公共)。
因为优化非常简单,几乎所有(或所有?)编译器都会这样做;许多编译器甚至在不太激进的优化级别(大多数优化被禁用)中都会这样做。
您将赋值运算符声明为按值使用参数并返回副本(不是引用),这很少见(但不非法):
/*Asgn 1*/ base operator=(base b){
cout<<" base::assignment - base"<<endl;
return b;
}
这意味着需要复制构造函数将参数传递给赋值运算符,并且还需要传递return
指令。
请注意,它是一个运营商的事实无关紧要,您可以称之为assign
:
/*Asgn 1*/ base assign(base b){
cout<<" base::assignment - base"<<endl;
return b;
}
并正常调用:
base a,b;
a.assign(b);
b.assign(base());
b.assign(base(2));
b.assign(3);
a.assign(b)
将调用复制构造函数来创建assign
。
base()
使用默认构造函数创建临时对象,base(2)
使用int
构造函数创建一个临时对象(当您显式创建临时对象时,它不无论构造函数是否为转换构造函数)。然后你可以assign
创建临时。编译器通过直接构造参数来避免复制构造。
在b.assign(3)
中,临时的创建是隐式的,构造函数是转换构造函数的事实是相关的。
return语句创建另一个副本; operator=
通常的习语是:
type& type::operator= (const type &source) {
copy stuff
return *this;
}
引用绑定到目标对象,不会发生冗余复制。