默认、参数化、复制构造函数和赋值运算符情况下的构造函数行为
Constructor behavior in case of default, parameterized, copy ctor and assignment operator
我正在经历 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 转换为基类型?
输出
default
base::int
base::assignment - base
base::cc
结果如下:
base b;
这里创建一个b
- 这将使用默认构造函数
int a = 10;
b = a;
我们有一个赋值 - 唯一可用的取一个 base
类型的值 - 所以编译器挠头说 "ah-ha" 得到了一个可以创建对象的构造函数版本从 int
输入 base
。我们可以使用它。
所以你得到了输出
cout<<" base::int "<<endl;
现在编译器可以使用赋值运算符了。该参数是一个 base
类型的对象,但由于它是临时的,因此不需要调用它(参见 http://en.cppreference.com/w/cpp/language/copy_elision),然后赋值运算符输出
cout<<" base::assignment - base"<<endl;
但是赋值 return 的值不作为引用 - 所以它需要将这个 return 值复制到 b
- 从而调用复制构造函数。因此
cout<<" base::cc "<<endl;
首先,base(int a)
是一个converting constructor as
需要一个参数
它不使用 explicit
关键字
转换构造函数可用于隐式转换:
void foo(base b);
void bar() {
foo(3);
}
此处 int
参数将使用转换构造函数隐式转换为 base
类型。
因为通过值参数(arguments by reference passed by reference)被复制,所以正式调用了复制构造函数;但是在这里,副本的源是一个临时对象,使用 int
构造函数隐式创建的对象。所以允许编译器融合临时对象和参数,直接构建目标对象。此优化是可选的,编译器仍必须验证是否可以调用复制构造函数:它已在此处声明并可访问 (public)。
因为优化非常简单,所以几乎所有(或所有?)编译器都会做;许多编译器甚至在不太激进的优化级别(大多数优化被禁用)都这样做。
您将赋值运算符声明为按值接受参数并 return 复制(而不是引用),这种情况很少见(但 不是 非法):
/*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
构造函数创建一个临时对象(当您显式创建临时对象时,它会 not 不管构造函数是否是转换构造函数)。然后你可以 assign
在创建的临时文件上。编译器通过直接构造参数来避免复制构造。
在b.assign(3)
中,临时对象的创建是隐式的,构造函数是转换构造函数这一事实是相关的。
return 语句创建另一个副本; operator=
的惯用法是:
type& type::operator= (const type &source) {
copy stuff
return *this;
}
引用绑定到目标对象,不会发生冗余复制。
我正在经历 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 转换为基类型?
输出
default
base::int
base::assignment - base
base::cc
结果如下:
base b;
这里创建一个b
- 这将使用默认构造函数
int a = 10;
b = a;
我们有一个赋值 - 唯一可用的取一个 base
类型的值 - 所以编译器挠头说 "ah-ha" 得到了一个可以创建对象的构造函数版本从 int
输入 base
。我们可以使用它。
所以你得到了输出
cout<<" base::int "<<endl;
现在编译器可以使用赋值运算符了。该参数是一个 base
类型的对象,但由于它是临时的,因此不需要调用它(参见 http://en.cppreference.com/w/cpp/language/copy_elision),然后赋值运算符输出
cout<<" base::assignment - base"<<endl;
但是赋值 return 的值不作为引用 - 所以它需要将这个 return 值复制到 b
- 从而调用复制构造函数。因此
cout<<" base::cc "<<endl;
首先,base(int a)
是一个converting constructor as
需要一个参数
它不使用
explicit
关键字
转换构造函数可用于隐式转换:
void foo(base b);
void bar() {
foo(3);
}
此处 int
参数将使用转换构造函数隐式转换为 base
类型。
因为通过值参数(arguments by reference passed by reference)被复制,所以正式调用了复制构造函数;但是在这里,副本的源是一个临时对象,使用 int
构造函数隐式创建的对象。所以允许编译器融合临时对象和参数,直接构建目标对象。此优化是可选的,编译器仍必须验证是否可以调用复制构造函数:它已在此处声明并可访问 (public)。
因为优化非常简单,所以几乎所有(或所有?)编译器都会做;许多编译器甚至在不太激进的优化级别(大多数优化被禁用)都这样做。
您将赋值运算符声明为按值接受参数并 return 复制(而不是引用),这种情况很少见(但 不是 非法):
/*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
构造函数创建一个临时对象(当您显式创建临时对象时,它会 not 不管构造函数是否是转换构造函数)。然后你可以 assign
在创建的临时文件上。编译器通过直接构造参数来避免复制构造。
在b.assign(3)
中,临时对象的创建是隐式的,构造函数是转换构造函数这一事实是相关的。
return 语句创建另一个副本; operator=
的惯用法是:
type& type::operator= (const type &source) {
copy stuff
return *this;
}
引用绑定到目标对象,不会发生冗余复制。