为什么要调用复制构造函数

时间:2019-01-24 11:29:23

标签: c++ constructor operator-keyword

我无法理解为什么调用拷贝构造函数而不是编译错误的原因。

我声明了两个A B类,它们是独立的。 A不是基于/派生于B。它们之间的唯一联系是在B中,我使用了将B转换为A的运算符 我已经定义了一个操作符=,它将B的const引用作为参数。 总的来说,我写了下面的B = A实例的实例。我希望会产生编译错误。但是运算符=称为

class A {};

class B {
public:
    // conversion from A (constructor):
    B()
    {

        cout << "1." << endl;
    }
    B(const A& x)
    {
        cout << "4." << endl;
    }
    // conversion from A (assignment):
    B& operator= (const B& x)
    {
        cout << "3." << endl;
        return *this;
    }
    // conversion to A (type-cast operator)
    operator A() {
        cout << "2." << endl;
        return A();
    }
};

int main()
{
    A foo;
    B bar;    // calls constructor
    bar = foo;      // calls assignment
                    //foo = bar;      // calls type-cast operator
    char c;
    c = getchar();
    return 0;
}

我期望编译错误。但是打印以下顺序 1 4 3。 我几乎无法理解复制构造函数的调用方式以及为什么operator =不会产生问题

谢谢

3 个答案:

答案 0 :(得分:3)

这不是您拥有的复制构造函数,而是转换构造函数。之所以调用转换构造函数,是因为您可以将A转换为B

执行以下操作:

explicit B(const A& x)

现在您将禁止从AB的隐式转换。

当您这样做:

bar = foo;

编译器寻找合理的操作,最多允许一次转换。它可以使用来自B的副本分配,并且知道可以从B中创建一个A(因为构造函数不是显式的),因此它会静默地执行此操作。

正如@lubgr所说,clang-tidy有一个规则来检查这些,这就是part of the C++ core guidelines

答案 1 :(得分:3)

您有一个隐式构造函数

list-style-position:outside

执行不需要的转换。您可以将签名更改为

B::B(const A&)

触发编译错误。请注意,优良作法是在默认情况下用一个参数explicit B(const A&); 标记构造函数(也有一个explicit check),只是为了避免偶然地进行此类转换(恕我直言,如果可以使用单个参数构造的构造函数默认情况下为clang-tidy并且具有隐式的功能,那就更好了。

答案 2 :(得分:2)

  

我希望会生成以下编译错误

no match for 'operator=' ... note: no known conversion for argument 1 from 'A' to 'const B&'

没有理由预料到这种错误,因为已知有一个从Aconst B&的转换。 B具有A的转换构造函数:

B(const A& x)

  

它们之间的唯一联系是在B中,我使用了将B转换为A的运算符

...,它们之间的第二个联系是在B中,您使用了一个将A转换为B的构造函数。

  

您是正确的,这是一个转换指导员。但是为什么在分配bar = foo发生时调用此方法。

因为赋值的给定操作数的类型为A,而声明的参数类型为const B&

在参数类型与声明不匹配的情况下,编译器将检查是否存在可用于转换参数的隐式转换序列。由于A可以隐式转换为B,所以这种隐式转换序列存在并将被使用。