Construction is a fairly hard topic in C++. The simple answer is it depends. Whether Foo is initialized or not depends on the definition of Foo itself. About the second question: how to make Bar initialize Foo: initialization lists are the answer.
While general consensus is that Foo will be default initialized by the implicit default constructor (compiler generated), that does not need to hold true.
If Foo does not have a user defined default constructor then Foo will be uninitialized. To be more precise: each member of Bar or Foo lacking a user defined default constructor will be uninitialized by the compiler generated default constructor of Bar:
class Foo {
int x;
public:
void dump() { std::cout << x << std::endl; }
void set() { x = 5; }
};
class Bar {
Foo x;
public:
void dump() { x.dump(); }
void set() { x.set(); }
};
class Bar2
{
Foo x;
public:
Bar2() : Foo() {}
void dump() { x.dump(); }
void set() { x.set(); }
};
template <typename T>
void test_internal() {
T x;
x.dump();
x.set();
x.dump();
}
template <typename T>
void test() {
test_internal<T>();
test_internal<T>();
}
int main()
{
test<Foo>(); // prints ??, 5, 5, 5, where ?? is a random number, possibly 0
test<Bar>(); // prints ??, 5, 5, 5
test<Bar2>(); // prints 0, 5, 0, 5
}
Now, if Foo had a user defined constructor then it would be initialized always, regardless of whether Bar has or not a user initialized constructor. If Bar has a user defined constructor that explicitly calls the (possibly implicitly defined) constructor of Foo, then Foo will in fact be initialized. If the initialization list of Bar does not call the Foo constructor then it will be equivalent to the case where Bar had no user defined constructor.
The test code may need some explaining. We are interested on whether the compiler does initialize the variable without the user code actually calling the constructor. We want to test whether the object is initialized or not. Now if we just create an object in a function it might happen to hit a memory position that was untouched and already contains zeroes. We want to differentiate luck from success, so we define a variable in a function and call the function twice. In the first run, it will print the memory contents and force a change. In the second call to the function, as the stack trace is the same, the variable will be held in exactly the same memory position. If it was initialized, it would be set to 0, else it would keep the same value the old variable in exactly the same position had.
In each of the test runs, the first value printed is the initialized value (if it was actually initialized) or the value in that memory position, that in some cases happen to be 0. The second value is just a test token representing the value at the memory position after manually changing it. The third value comes from the second run of the function. If the variable is being initialized it will fall back to 0. If the object is not initialized, its memory will keep the old contents.