关于构造函数匹配和隐式转换的问题

Question about constructor matching and implicit conversion

我正在参加旧学校考试以准备我当前的考试,并且在其中一个问题中我得到了以下代码:

#include <iostream>
using namespace std;

struct A
{
  A() : m_a(17) { cout << "A_default" << endl; }
  int m_a;
};

struct B1 : A
{
  B1() : m_b(1) { cout << "B1_default" << endl; }
  B1(const A& a)
  {
    cout << "B1_constructor_with_a_parameter_A" << endl;
    m_b = a.m_a + 1;
  }
  int m_b;
};

struct B2 : A
{
  B2() : m_b(1) { cout << "B2_default" << endl; }
  B2(const B1& b1)
  {
    cout << "B2_constructor_with_a_parameter_B1" << endl;
    m_b = b1.m_b + 100;
  }
  int m_b;
};



int main() 
{
  A a1;
  B1 b1;
  B2 b2 = b1;
  A a2 = b2;
  B1 b3 = b1;
  B1 b4 = b2;
  return 0;
}

此代码打印:

A_default
A_default
B1_default
A_default
B2_constructor_with_a_parameter_B1
A_default
B1_constructor_with_a_parameter_A

任务是将每个打印行与 main 中相应的代码行匹配。除了最后一行 B1_constructor_with_a_parameter_A 之外,我都做对了。答案 sheet 表示此打印行来自 main() 中的 B1 b4 = b2; 行,但没有解释为什么会发生这种情况。

所以我的问题很简单。 为什么 B1 b4 = b2; 不匹配 struct B1 中的任何构造函数模式时打印 B1_constructor_with_a_parameter_A 是否存在某种奇怪的对象切片或隐式转换发生在这里?这是我最好的猜测。我有点困惑。

如果确实发生对象切片或隐式转换。为什么行 B1 b3 = b1; 不打印任何内容?除了 b2 是 B2 类型和 b1B1 类型之外,我看不出 B1 b3 = b1;B1 b4 = b2; 之间有什么区别。既然它们都继承了 A,难道不应该应用相同的规则吗?我很困惑。

Why does B1 b4 = b2; print B1_constructor_with_a_parameter_A when it doesn't match any constructor pattern in struct B1?

它这样做是因为 b2 是继承自 AB2 类型,这使得它可以隐式转换为 A.

Why doesn't the line B1 b3 = b1; print anything?

因为这行 copy-constructor(由编译器提供)调用了 B1,因为两者都是 相同的 类型。在 B1 = B2 的情况下,唯一匹配的构造函数是 B1(const A& a)。因此,它隐式转换为 A.

类型

这样的行为和代码很糟糕,这正是我们应该编写构造函数的原因 explicit。编译上面的代码并做以下更改,你会发现它不再隐式转换了:

explicit B1(const A& a) { cout << "B1_constructor_with_a_parameter_A" << endl; }