关于构造函数匹配和隐式转换的问题
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
类型和 b1
是 B1
类型之外,我看不出 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
是继承自 A
的 B2
类型,这使得它可以隐式转换为 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; }
我正在参加旧学校考试以准备我当前的考试,并且在其中一个问题中我得到了以下代码:
#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
类型和 b1
是 B1
类型之外,我看不出 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 instruct B1
?
它这样做是因为 b2
是继承自 A
的 B2
类型,这使得它可以隐式转换为 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; }