kc@rna.UUCP (Kaare Christian) (05/26/89)
A question, if you please. I have a class that has several constructors. class X { ... public: X(); X(int n); All of these constructors have some mundane chores that must be accomplished, plus there are extra chores for those that take extra arguments. What I tried to do was have the "parameter taking" constructors all call the parameterless constructor. So, I had something like X::X(int n) { X(); // the extra work } This didn't work, the call to X() created a new object, it didn't initialize the current object. (I guess this makes sense, 'cause a statement like A=X() should create a new object.) Then I tried X::X(int n) { this->X(); // the extra work here } But this didn't pass muster, Zortech C++ complained that "X wasn't a member of class X." Is there a way for one constructor to call another, simply to have some chores performed, while avoiding real construction? (I know I can have all the constructors call some helper function, but that seems too roundabout.) Thanks, Kaare Christian
ark@alice.UUCP (Andrew Koenig) (05/27/89)
In article <601@rna.UUCP>, kc@rna.UUCP (Kaare Christian) writes: > Is there a way for one constructor to call another, simply to have > some chores performed, while avoiding real construction? Nope. Roundabout or not, the best way to do it is with helper functions. However, if you really insist, C++ 2.0 will have a way to say `construct an object of type T at location X," as follows: new (X) T (args); So by saying new (this) T (args); you will, in effect, be able to call one constructor from another. Having called this operator new, you'll need to define it: void* operator new(size_t,T* tp) { return tp; } and then you're in business. I said `if you really insist' because I think it's conceptually cleaner to use helper functions and it is probably worthwhile not to cut yourself off from older C++ implementations. -- --Andrew Koenig ark@europa.att.com
sarima@gryphon.COM (Stan Friesen) (05/28/89)
In article <601@rna.UUCP> kc@rna.UUCP (Kaare Christian) writes: >A question, if you please. > >I have a class that has several constructors. >[Examples deleted] >All of these constructors have some mundane chores that must be accomplished, >plus there are extra chores for those that take extra arguments. What I tried >to do was have the "parameter taking" constructors all call the >parameterless constructor. > >This didn't work, the call to X() created a new object, it didn't >initialize the current object. > >>[Other failed approach deleted] >Is there a way for one constructor to call another, simply to have >some chores performed, while avoiding real construction? (I know I can >have all the constructors call some helper function, but that >seems too roundabout.) > What's so round-about in using a helper function? Especially since the helper can be made a private function, used only in constructors? It is also quite readable. -- Sarima Cardolandion sarima@gryphon.CTS.COM aka Stanley Friesen rutgers!marque!gryphon!sarima Sherman Oaks, CA
shopiro@alice.UUCP (Jonathan Shopiro) (05/30/89)
In article <9396@alice.UUCP>, ark@alice.UUCP (Andrew Koenig) writes: > In article <601@rna.UUCP>, kc@rna.UUCP (Kaare Christian) writes: > > > Is there a way for one constructor to call another, simply to have > > some chores performed, while avoiding real construction? > > Nope. Roundabout or not, the best way to do it is with > helper functions. > > However, if you really insist, C++ 2.0 will have a way to say > `construct an object of type T at location X," as follows: > > new (X) T (args); > > So by saying > > new (this) T (args); > This approach should be avoided. If you use it, you will initialize an object twice. For example struct M { M(); }; struct S { M mem; S(); S(int); }; S::S(int) { new (this) S; // take care of mundane chores // other less mundane chores } // ... S s(3); When the object s is initialized, its member s.mem will be initialized twice because each time a constructor of class S is invoked, all members and bases of S are initialized by compiler-synthesized code. It is fundamental to the C++ notion of object, that each object is initialized once when it comes into existence and destroyed once when it disappears. In practice, surprisingly many classes depend on this invariant and their constructors will misbehave if they are invoked twice on the same object. The new ``placement'' syntax that Andy mentioned was introduced to permit objects to be initialized in a user-specified location (e.g., in shared memory), rather than to support invocation of constructors on already-initialized objects. The fact that the latter is not prohibited is unfortunate. An alternative approach to Kaare's problem would be to rely on compiler-synthesized code to do the ``mundane chores.'' The most extreme example of this would be to create a new class publicly derived from the original class and move the fancy constructors to the new class. The original class should be renamed and its original name given to the new class. For example, class Old_X { friend X; Old_X(); // all the private members from the original X public: // all the public members of the original X, save constructors }; class X : public Old_X { public: X() {} // the no-arg constructor just invokes // the one from the base class X(int n); // nothing else }; Old_X::Old_X() { // mundane chores here } X::X(int n) { // Old_X::Old_X() is invoked automagically // the extra work } Note in the above that since the constructor of Old_X is private, it can't be instantiated by itself, but only as a base of an X object. Also, the program is more reliable because the Old_X constructor is only invoked by compiler-generated code. The user is supposed to ignore the existence of Old_X and just use X. You can discourage the user from trying to access Old_X apart from X by giving it a very long name. It is often the case that you don't need to go to the trouble of defining an extra class for this problem. Perhaps the initializers of the bases and members that are already there are sufficient. Or maybe a helper function is the best choice after all! :-) -- Jonathan Shopiro AT&T Bell Laboratories, Warren, NJ 07060-0908 research!shopiro (201) 580-4229