Case I
Lets consider SalesData s; .
In this case an object of type SalesData with name s is constructed using the default constructor of SalesData. Also, note that in this case the variable s is a local nonstatic.
Next since you :
- didn't Use in-class initializers to initialize
unitsSold and revenue
- didn't Use constructor initializer list to initialize
unitsSold and revenue
These 2 variables hold indeterminate value. And using these uninitialized variables leads to undefined behavior.
This means when you wrote:
print(cout, s);//this calls print function
And inside the print function's body you have:
os << "ISBN :\'" << item.isbn() << "\', Units Sold :" << item.unitsSold
<< ", Revenue :" << item.revenue << ", Avg. Price :"
<< item.avgPrice() << std::endl; //this is undefined behavior
So in the above statement you're using the uninitialized variables unitsSold and revenue and this results in undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.
This is the reason you saw those numbers(garbage values) like 3417894856 and 4.66042e-310 in this case. So don't rely on the output of your program since it has undefined behavior.
Case II
Now lets consider static SalesData s2;
From Static local variables' initialization documentation:
Variables declared at block scope with the specifier static or thread_local (since C++11) have static or thread (since C++11) storage duration but are initialized the first time control passes through their declaration (unless their initialization is zero- or constant-initialization, which can be performed before the block is first entered).
Now from zero initialization documentation:
Zero initialization is performed in the following situations:
- For every named variable with static or thread-local (since C++11) storage duration that is not subject to constant initialization, before any other initialization.
Here comes the most relevant part:
The effects of zero initialization are:
If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.
Lets apply these above quoted statements to your example static SalesData s2;
In this case the variable s2 is a local static. Here 2 things happen:
- the variable
s2 is zero initialized. This means all of its non-static data members like unitsSold and revenue are set to 0 according to the above quoted statement. This is the reason the output numbers in this case are all 0 instead of some garbage values.
- Next the variable
s2 is default initialized using the default constructor.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.