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 explicit
ness 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 constructorBase(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.
精彩评论