默认情况下的构造函数行为,参数化,复制ctor和赋值运算符

时间:2015-08-23 09:59:40

标签: c++ copy-constructor implicit-conversion 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;
}

输出:

program output

有人可以解释一下输出吗? 我只想打电话给

  1. 默认构造函数。
  2. 参数化构造函数。
  3. 我无法理解为什么我调用赋值运算符和复制构造函数的其他对象是“int”类型。如果我取消注释“Asgn 2”,我会打电话给它而不是Asgn 1这是可以理解的。

    如果我正在调用复制构造函数(它总是以对象引用作为参数),那是因为编译器将int转换为基类型吗?

2 个答案:

答案 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;
}

引用绑定到目标对象,不会发生冗余复制。