I'm curious of how C++ primitive built in types, int for instance, are initialized in comparison to objects of a class.
After doing research I learned that C++ is a statically typed language meaning type checking is done at compile-time not run-time. This means, that primitive types are not objects of a class and a types cannot change.
So what differs in the following object initializations:
class Foo
{
public:
int num;
Foo(int n) : num(n) {}
};
Foo bar(5);
Foo bar2{ 5 };
Foo bar3 = 5;
To the primitive initializations:
int num(5);
int num2{ 5 };
int num3 = 5;
I know instances of Foo call the constructor to initialize but what does the primitive call or do to initialize if it is not an object?
Furthermore what else fundamentally distinguishes the types Foo & int, other than Foo being "a user defined blue print to create instances" and int being "a non object built in type".
For a class with user-defined constructors like Foo
, the only difference between the initializations is that the last (called copy-initialization ) is equivalent to
Foo bar3 = Foo(5);
That is, the initializer expression is converted to the class type ( via a constructor) and then bar3
is initialized from that . (Until C++17 this notionally involves a copy or move, but compilers routinely avoid that overhead.)
Note that there is one more syntax:
Foo bar4={5};
This is known as copy-list-initialization , but the only difference from the version without the =
is that explicit
constructors are disallowed.
The lack of significant differences between these forms fails to motivate having them and is therefore confusing. The distinction comes with containers , broadly construed so as to include aggregates (simple C-like struct
s). Those support {}
-initialization with a different meaning, which is to construct an object containing some data, rather than computed from it. So
std::vector<double> a(10,1),b{10,1};
defines a
to have 10 values (which are each 1) and b
to have the two values 10 and 1.
It has been suggested that use of braces to initialize should be restricted to this meaning to avoid confusion.
Finally, we have your int
examples. It should be clear now that all the initializations are interchangeable (except that list-initialization prohibits narrowing conversions), since there is no distinction between computing a primitive value and filling it. Nor is there any possibility of observing the initialization of (or assignment to) a variable of primitive type: it simply comes to have the value supplied as an atomic action of the abstract machine. (Compilers know this and elide as many such variables as they can for efficiency.)
Even an int
is an object (in the C++ sense of that word, not the Java or Python sense), and when you have a Foo
you have two objects: the Foo
itself and the int num
it contains (which is created and destroyed along with it). So your initializations of Foo
objects are also two initializations each: the outer one consisting of the inner one (which is always performed by the num(n)
member-initializer ).
It is the existence of this extra object that distinguishes Foo
from int
, without having to define a class operationally in terms of a memory layout: the operations allowed on a Foo
are in general different because it is distinct from any object(s) it might contain.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.