These two class declarations are not equivalent.
In the second class declaration, the constructor is declared with the explicit function specifier, and this limits the use of this constructor in various situations.
In the first class declaration, only the conversion constructor is declared with the function specifier explicit . This means that you can call other constructors implicitly.
That is, the first declaration provides more options for using the class.
View the following demo.
#include <iostream> struct A { explicit A( int x = 0, int y = 0 ) : x( x ), y( y ) {} int x; int y; }; struct B { B() : x( 0 ), y( 0 ) {} explicit B( int x ): x( x ), y( 0 ) {} B( int x, int y ): x( x ), y( y ) {} int x; int y; }; void f( const A &a ) { std::cout << "ax = " << ax << ", ay = " << ay << std::endl; } void g( const B &b ) { std::cout << "bx = " << bx << ", by = " << by << std::endl; } int main() { // f( {} ); // f( { 1, 2 } ); g( {} ); g( { 1, 2 } ); }
Its output to the console:
bx = 0, by = 0 bx = 1, by = 2
In this program, the two function calls f commented out, because if uncommented them, the compiler will give an error message.
Another important difference is that one class has only one constructor with a given signature, and the other class has three constructors with different signatures.
View another demo.
struct A { explicit A( int x = 0, int y = 0 ) : x( x ), y( y ) {} int x; int y; }; struct B { B() : x( 0 ), y( 0 ) {} explicit B( int x ): x( x ), y( 0 ) {} B( int x, int y ): x( x ), y( y ) {} int x; int y; }; struct C { //friend A::A(); friend B::B(); }; int main() { }
Here in class C you can declare the default constructor of class B as a friend of class C However, you cannot do the same with the default constructor of class A to declare it a friend of class C , since the default constructor in class A has a different signature.
You already have to write
struct C { friend A::A( int, int ); };
this may not be what you would like to receive. That is, if you, for example, wanted a friend to be a constructor, which is called exclusively without arguments.
That is, again, when there are separate designers, then your possibilities are broader.
If we consider not designers, but functions, then the difference is even more significant.
Arguments by default do not affect the type of function. Therefore, for example, if you declare a function as
void f( int, int = 0 );
then despite the default argument and the fact that you can call it as
f( value );
however, its type is void( int, int ) . And this in turn means that you cannot, for example, write
void h( void f( int ) ) { f( 10 ); } void f( int x, int y = 0 ) { std::cout << "x = " << x << ", y = " << y << std::endl; } // h( f );
since the parameter of the function h has the type void( int ) ., and the function used as an argument has the type void( int, int )
If you declare two functions instead of one
void h( void f( int ) ) { f( 10 ); } void f( int x ) { std::cout << "x = " << x << std::endl; } void f( int x, int y ) { std::cout << "x = " << x << ", y = " << y << std::endl; }
this challenge
h( f );
will be correct, as there is a function with one parameter.