开发者

Effect of `explicit` on static upcasting

May an instance of a derived class be implicitly converted to an instance of its base class, when the only candidate constructor in the base class is marked explicit?


I ran this:

struct Base {
   Base() {}
   explicit Base(Base const& b) {}
};

struct Derived : Base {};

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

And got this:

error: no matching function for call to 'Base::Base(Derived&)'

Then I ran this:

struct Base {
   B开发者_运维技巧ase() {}
   Base(Base const& b) {}
};

struct Derived : Base {};

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

And got no errors.

But I'm not entirely convinced that this test succeeds due to explicitness rather than ctor synthesis. In particular, I didn't think that explicit cared about the type of arguments, but that it would force me to write Base b = static_cast<Base>(d) ... which I'm not doing in either case.


It's not the conversion that fails. Copy-initialization requires an accessible copy-constructor.

This also fails:

struct Base {
   Base() {}
   explicit Base(Base const& b) {}
};

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


In hindsight, it seems clear.

The elements at play here are:

  • The only would-be-synthesised candidate constructor is Base(Base const&), and I don't provide a constructor Base(Derived const&).
  • Said constructor is explicit, but I provide no explicit conversion.

So, the answer is "no".


This:

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

is not upcasting. That is creating a new object, called b, which contains a copy of the value of d. In order to have upcasting, you must be using polymorphic values (references or pointers). Upcasting would therefore be:

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

The variable b contains a reference to the Base part of d. If Base had some public member int baseValue;, then b.baseValue refers to the exact same data as d.baseValue. For example:

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

This will write 10. If b weren't a reference, but a regular object, it would have copied the (initialized) value from d before d's value was changed. And therefore changing one would not change the other.

The purpose of the explicit keyword is to prevent syntax like Base b = d from working. If you make a constructor explicit, you are saying, "I don't want the compiler to ever implicitly call this copy constructor. If the user is to use it, then they must explicitly say so." If you want implicit conversion of types, then you must say so.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜