I understand benefits of dependency injection itself. Let\'s take Spring for instance. I also understand benefits of other Spring featureslike AOP, helpers of different kind
Dependency injection is a coding style that has its roots in the observation that object delegation is usually a more useful design pattern than object inheritance (i.e., the object has-a relationship is more useful than the object is-a relationship). One other ingredient is necessary however for DI to work, that of creating object interfaces. Combining these two powerful design patterns software engineers quickly realized that they could create flexible loosely coupled code and thus the concept of Dependency Injection was born. However it wasn't until object reflection became available in certain high level languages that DI really took off. The reflection component is core to most of today's DI systems today because the really cool aspects of DI require the ability to programmatically select objects and configure and inject them into other objects using a system external and independent to the objects themselves.
A language must provide good support for both normal Object Oriented programming techniques as well as support for object interfaces and object reflection (for example Java and C#). While you can build programs using DI patterns in C++ systems its lack of reflection support within the language proper prevents it from supporting application servers and other DI platforms and hence limits the expressiveness of the DI patterns.
Strengths of a system built using DI patterns:
Definitely DI code seems more cumbersome, the disadvantages of having all of those XML files that configure objects to be injected into other objects appears difficult. This is, however, the point of DI systems. Your ability to mix and match code objects as a series of configuration settings allows you to build complex systems using 3rd party code with minimal coding on your part.
The example provided in the question merely touches on the surface of the expressive power that a properly factored DI object library can provide. With some practice and a lot of self discipline most DI practitioners find that they can build systems that have 100% test coverage of application code. This one point alone is extraordinary. This is not 100% test coverage of a small application of a few hundred lines of code, but 100% test coverage of applications comprising hundreds of thousands of lines of code. I am at a loss of being able to describe any other design pattern that provides this level of testability.
You are correct in that an application of a mere 10s of lines of code is easier to understand than several objects plus a series of XML configuration files. However as with most powerful design patterns, the gains are found as you continue to add new features to the system.
In short, large scale DI based applications are both easier to debug and easier to understand. While the Xml configuration is not 'compile time checked' all application services that this author is aware of will provide the developer with error messages if they attempt to inject an object having an incompatible interface into another object. And most provide a 'check' feature that covers all known objects configurations. This is easily and quickly done by checking that the to-be-injected object A implements the interface required by object B for all configured object injections.