A Constructor initializes a object that doesn't exist. A Method does operations on an already created object. A Constructor's name must be same as the name of the class. A Method's name can be anything.
A class object with a constructor must be explicitly initialized or have a default constructor. Except for aggregate initialization, explicit initialization using a constructor is the only way to initialize non-static constant and reference class members.
I recommend initializing variables in constructors. That's why they exist: to ensure your objects are constructed (initialized) properly. Either way will work, and it's a matter of style, but I prefer constructors for member initialization.
A constructor is similar to method and it is invoked at the time creating an object of the class, it is generally used to initialize the instance variables of a class. The constructors have same name as their class and, have no return type.
Since they say "timing", I guess it's because they want their init functions to be able to call virtual functions on the object. This doesn't always work in a constructor, because in the constructor of the base class, the derived class part of the object "doesn't exist yet", and in particular you can't access virtual functions defined in the derived class. Instead, the base class version of the function is called, if defined. If it's not defined, (implying that the function is pure virtual), you get undefined behavior.
The other common reason for init functions is a desire to avoid exceptions, but that's a pretty old-school programming style (and whether it's a good idea is a whole argument of its own). It has nothing to do with things that can't work in a constructor, rather to do with the fact that constructors can't return an error value if something fails. So to the extent that your colleagues have given you the real reasons, I suspect this isn't it.
Yes I can think of several, but generally it's not a good idea.
Most of the times the reason invoked is that you only report errors through exceptions in a constructor (which is true) whereas with a classic method you can return an error code.
However in properly designed OO-code the constructor is responsible for establishing the class invariants. By allowing a default constructor, you allow an empty class, thus you have to modify the invariants so that is accepted both the "null" class and the "meaningful" class... and each use of the class must first ensure that the object has been properly built... it's crass.
So now, let's debunk the "reasons":
virtual
method: use the Virtual Constructor idiom.assert
at the beginning of each public method to make sure the object is usable before trying to use it.operator=
(and implement it using the copy and swap idiom if the compiler generated version does not suit your need).As said, in general, bad idea. If you really want to have "void" constructor, make them private
and use Builder methods. It's as efficient with NRVO... and you can return boost::optional<FancyObject>
in case the construction failed.
Others have listed lots of possible reasons (and proper explanations of why most of these are generally not a good idea). Let me post one example of a (more or less) valid use of init methods, which actually has to do with timing.
In a previous project, we had lots of Service classes and objects, each of which were part of a hierarchy, and cross referencing each other in various ways. So typically, for creating a ServiceA, you needed a parent service object, which in turn needed a service container, which already depended on the presence of some specific services (possibly including ServiceA itself) at initialization time. The reason was that during initialization, most of the services registered itself with other services as listeners to specific events, and/or notified other services about the event of successful initialization. If the other service did not exist at the time of notification, the registration did not happen, thus this service would not receive important messages later, during the usage of the application. In order to break the chain of circular dependencies, we had to use explicit initialization methods separate from constructors, thus effectively making global service initialization a two-phase process.
So, although this idiom should not be followed in general, IMHO it has some valid uses. However, it is best to limit its usage to the minimum, using constructors whenever possible. In our case, this was a legacy project, and we didn't yet fully understand its architecture. At least the usage of init methods was limited to the service classes - regular classes were initialized via constructors. I believe there might be a way to refactor that architecture to eliminate the need for service init methods, but at least I did not see how to do it (and to be frank, we had more urgent issues to deal with at the time I was part of the project).
Two reasons I can think of off the top of my head:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With