Software Design & Engineering Internet business development mobile applications |
Alan Partis |
320 Ridgecreek Drive Lexington, SC 29072 (803) 692-1101 alpartis@thundernet.com |
|
|
|
C++ Constructor Chaining January, 2014This will come as a shock to some people: it is my very nature to be lazy. Really. The truth is, this is actually a very positive trait for good software engineers. With this in mind, in years past when I set up a new class with multiple constructors to give my users flexibility and clarity, and to make maintenance easier, I would construct something like the following, with a private init() function. This function provides default initial values that each constructor can then override with user-supplied values as necessary.
This approach has worked well since the 20th century, though it does require each constructor to explicitly call init(). Not too bad, but still with a bit more excess typing than I like. Quick 21st century interview question: "Mr. Partis, can you call a class constructor from another constructor of the same class? ... and get all your member initialization correct? ... and conform to the DRY principle (Don't Repeat Yourself)? That's easy. I'd write something like this:
Here we still have the default no-arg constructor where we initialize the values for our member attributes. Then an alternative ctor taking one argument, chains a call to the default constructor and then overrides the value for member _x. Perfect. Concise. Just my style. Constructor chaining, "delegation" as they call it, is allowed in C++, but not prior to the C++11 standard. It's a handy feature. One thing I'd like to point out to prevent some problems. Take note of the fact that the constructor chaining / delegation takes place in the member initialization list, not in the body of the constructor. Consider this example:
This version will compile and run, but the result may be 'surprising' to you (I ran into this myself and lost a few embarrassing hours working out the subtle problem). The caller to the constructur on line 15 is setting up a new object of this type and passing in a value of x to use for initialization. Line 17 then invokes the default no-arg constructor of line 8 and creates an new object where x is 0 and y is 523. Then on line 18 we assign the user-provided x and return. The problem is, line 17 created a NEW object of type SubtleBug on our local stack with the initial 0 and 523 values, but this is NOT the object that the caller is constructing -- and that object on our stack will be discarded when it goes out of scope at line 19. In the mean time, all we did was initialize our _x member, but left _y at its default. Constructor delegation is a handy feature, but be sure you use it from the initialization list, not from the constructor body. You'll get much better mileage that way! |
"Thundernet" is a trademark of Thundernet Development Group, Inc. a Florida corporation. |
Copyright © Thundernet Development Group, Inc.. All rights reserved. |