【问题标题】:Question about constructor matching and implicit conversion关于构造函数匹配和隐式转换的问题
【发布时间】:2023-04-04 11:36:01
【问题描述】:

我正在为我当前的考试做准备,并且在其中一个问题中我得到了这个代码:

#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,我已经把它们都弄对了。答案纸上说这条打印线来自main() 中的B1 b4 = b2; 行,但没有解释为什么会发生这种情况。

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

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

【问题讨论】:

  • @t.niese 那为什么B1 b3 = b1; 不打印任何东西? B1 b4 = b2;B1 b3 = b1; 之间似乎没有区别,只是 b2 属于 B2 类型,而 b1 属于 B1 类型。不应该适用相同的规则吗?
  • 这里使用的命名约定是垃圾。将 B1 重命名为 B,将 B2 重命名为 C,然后将 B 类型的变量重命名为 b,将 C 类型的变量重命名为 c。这清楚地表明了表达式中使用的类型,而不是让它成为愚蠢的猎鹅。
  • @Yakk-AdamNevraumont 所说的非常真实。我不得不多次阅读以确保我是正确的。如果您想理解代码,如果您使用不会混淆的正确命名,您会更容易。

标签: c++ constructor instantiation implicit-conversion object-slicing


【解决方案1】:

为什么B1 b4 = b2;struct B1 中的任何构造函数模式都不匹配时会打印B1_constructor_with_a_parameter_A?

之所以这样做是因为b2B2 类型,它继承自A,这使得它可以隐式转换为A

为什么B1 b3 = b1; 行不打印任何内容?

因为这一行调用了 B1 的复制构造函数(由编译器提供),因为两者都是 相同的 类型。对于B1 = B2,唯一匹配的构造函数是B1(const A&amp; a)。因此,它隐式转换为类型A

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

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

【讨论】:

  • Soo...据我所知,复制构造函数总是优先于普通构造函数,这就是为什么B1 b3 = b1; 与复制构造函数匹配之前(可能)与B1(const A&amp; a) 匹配构造函数......或者它是否与该构造函数不匹配(即使复制构造函数“不可用”)?
  • 不,没有优先级。假设您有一个A a1 类型的对象,并且您创建了另一个A 类型的对象,例如:A a2 = a1,将调用复制构造函数。当类型相同时,使用复制构造函数来构造对象。
  • 是的,即使你删除了复制构造函数,B1(const A&amp; a) 也不会被调用。
猜你喜欢
  • 1970-01-01
  • 2011-09-18
  • 2014-06-13
  • 2012-04-29
  • 2014-07-26
  • 2013-11-02
  • 2020-06-20
  • 2011-06-08
  • 1970-01-01
相关资源
最近更新 更多