#include <iostream>
using namespace std;
struct Foo {
Foo() {
cout<<"Default constructor."<<endl;
}
Foo(Foo const&) {
cout<<"Copy constructor."<<endl;
}
Foo(int) {
cout<<"Conversion constructor."<<endl;
}
Foo& operator = (int) {
cout<<"Assignment operator."<<endl;
return *this;
}
};
int main() {
Foo a(1);
Foo b = 1;
Foo c = Foo(1);
return 0;
}
Do you know what this program will output?
I have the impression that most C programmers will tell you that the first will invoke the conversion constructor, but will be split on whether the second and third forms call the conversion constructor and the assignment operator, or the conversion constructor and the copy constructor. This means that I have the impression that most C programmers don’t know what these statements really mean to the C++ compiler.
The Form Type t = expr;
The expression Foo b = 1;
is an alternate way of saying Foo b(1);
. Both
are considered forms of direct initialization by the C++ language
specification, so no assignment or copy constructor is invoked. In a
statement which declares and initializes a variable, the =
is not a true
assignment operator, but an indication to the compiler of how to initialize
the value.
The Form Type t = Type(expr);
In C++, constructors don’t really have names. The syntax
Foo(1);
is not really considered a function call (where the function happens to be a
constructor), it is actually considered to be an explicit type conversion
from 1
to Foo. This is commonly called a function-style cast and is closer
to int(5.3f)
than a function call. The only difference is that multiple
values can be used in a function-style cast for user-defined types.
If we combine these facts, we can conclude that the statement
Foo c = Foo(1);
only invokes the conversion constructor as well. The =
indicates initialization and the Foo(1)
only casts the type; therefore,
again, only the conversion constructor is called.
Other Conversions
Since constructors are invoked for conversions, there are other forms which are simply constructor invocations:
(Foo) 1;
static_cast<Foo>(1);
Both of these could replace Foo(1)
above without changing the meaning of
the statement.