“explicit”对静态上播的影响

Effect of `explicit` on static upcasting

本文关键字:影响 静态 explicit      更新时间:2023-10-16

当基类中唯一的候选构造函数被标记为explicit时,派生类的实例是否可以隐式转换为基类的实例?


我运行了这个:

struct Base {
   Base() {}
   explicit Base(Base const& b) {}
};
struct Derived : Base {};
int main() {
   Derived d;
   Base b = d;
}

得到这个:

错误:没有匹配的函数调用'Base::Base(Derived&)'

然后我运行这个:

struct Base {
   Base() {}
   Base(Base const& b) {}
};
struct Derived : Base {};
int main() {
   Derived d;
   Base b = d;
}

没有错误。

但我不完全相信这个测试的成功是由于explicit而不是由于合成。特别是,我不认为explicit关心参数的类型,但它会迫使我写Base b = static_cast<Base>(d)…这两种情况我都不做

不是转换失败。复制初始化需要一个可访问的复制构造函数。

struct Base {
   Base() {}
   explicit Base(Base const& b) {}
};
int main() {
   Base d;
   Base b = d;
}

事后看来,似乎很清楚。

在这里起作用的元素有:

  • 唯一要合成的候选构造函数是Base(Base const&),我不提供构造函数Base(Derived const&)
  • 所述构造函数是explicit,但我没有提供显式转换。

所以,答案是"不"

This:

int main() {
   Derived d;
   Base b = d;
}

不是向上转换。这就是创建一个名为b新对象,它包含d值的副本。为了进行上转换,必须使用多态值(引用或指针)。因此,向上转换将是:

int main() {
   Derived d;
   Base &b = d;
}

变量b包含对dBase部分的引用。如果Base有某个公共成员int baseValue;,则b.baseValue引用的数据与d.baseValue完全相同。例如:

int main() {
   Derived d;
   Base &b = d;
   d.baseValue = 10;
   cout << b.baseValue << endl;
}

这将写10。如果b不是一个引用,而是一个普通对象,那么在d的值被改变之前,它会从d复制(初始化)的值。因此,改变其中一个不会改变另一个。

explicit关键字的目的是防止像Base b = d这样的语法起作用。如果你创建了一个构造函数explicit,你是在说,"我不希望编译器隐式地调用这个复制构造函数。如果用户要使用它,那么他们必须明确地这样说。如果你想隐式转换类型,那么你必须这样说。