Right, so let me start off by saying you've created a truly messed up type hierarchy. If you were trying to understand initialization order, this example is only likely to confuse you.
Anyway, to make things clearer, I modified your code and added a slash / character to the end of each c'tor print statement. So we can more easily discern what part of the line belongs to each c'tor. This gives the following output:
1A7/23/33/1A7/44/5
Before I get to the initialization order, you should know that all the virtual functions you specified won't by dynamically dispatched. A virtual function in the c'tor body will be statically bound. So for our intents and purposes, you don't really have virtual functions called in your code.
Now, to quote the C++ standard, this is how the initialization order will be determined ([class.base.init]/13):
In a non-delegating constructor, initialization proceeds in the
following order:
First, and only for the constructor of the most derived class, virtual base classes are initialized in the order they appear on a
depth-first left-to-right traversal of the directed acyclic graph of
base classes, where “left-to-right” is the order of appearance of the
base classes in the derived class base-specifier-list.
Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of
the mem-initializers).
Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the
mem-initializers).
Finally, the compound-statement of the constructor body is executed.
So let's break your initialization apart:
1) The virtual A sub-object is default constructed, since you didn't specify it in the member initializer list of E(), it executes A() for the object that is shared for B and C, and prints 1A7/.
2) Now the c'tor for B is called, executing B(int i) with i = 2. It sets B::i to 3, and the c'tor body prints 23/.
3) C is constructed by calling C(int i) with i = 3. This prints 33/.
4) Now it's time to construct D. So you call D(int i) with i = 4. Since D inherits from A non-virtually, it will have a distinct A sub-object that needs construction now.
You again didn't specify a parameter for it in the member initializer list, so A is default constructed. This prints 1A7/.
Now the body of D(int i) runs, and prints 44/.
5) Finally, the body of E() is called, and prints 5.