eda@persoft.com (Ed Almasy) (02/01/91)
This has been puzzling me for some time, and I'm hoping that someone here can explain it. Assuming: A is a class, with a constructor that requires 3 arguments B is a class, containing a member of type A C is a struct, containing a member of type A My question is: When I create data items of type B or C, where do the constructor arguments for the member that is of type A come from? Do I have to put them in my declaration for B or C, or is there a way to specify them at run time? If so, what is the proper syntax? Up until now I've just avoided this situation by coding around it, but it's about time for me to stop weaseling around the issue and code these things the way they should be. :-) Thanks!
rmartin@clear.com (Bob Martin) (02/04/91)
In article <1991Jan31.194631.3447@persoft.com> eda@persoft.com (Ed Almasy) writes: >This has been puzzling me for some time, and I'm hoping that someone >here can explain it. > >Assuming: > A is a class, with a constructor that requires 3 arguments > B is a class, containing a member of type A > C is a struct, containing a member of type A > >My question is: When I create data items of type B or C, where do the >constructor arguments for the member that is of type A come from? Do I >have to put them in my declaration for B or C, or is there a way to >specify them at run time? If so, what is the proper syntax? > Refer to ARM 12.1 concerning constructors and 12.6.2 concerning member initialization. You can proceed in one of two ways. Either create a "default constructor" for class A. (You must do this since the compiler wont do it for you if you have declared other constructors for A). Then when B or C are constructed the default constructor will be used for A. Or you can provide the Constructors of B and C with member initialization lists which will construct A for you. You can specify all 3 parameters in the member intialization list. class B { A theA; }; // B constructor. B::B(a,b,c) : theA(a,b,c) // <- member intialization list { ... code for B construction } -- +-Robert C. Martin-----+:RRR:::CCC:M:::::M:| Nobody is responsible for | | rmartin@clear.com |:R::R:C::::M:M:M:M:| my words but me. I want | | uunet!clrcom!rmartin |:RRR::C::::M::M::M:| all the credit, and all | +----------------------+:R::R::CCC:M:::::M:| the blame. So there. |
sarima@tdatirv.UUCP (Stanley Friesen) (02/04/91)
In article <1991Jan31.194631.3447@persoft.com> eda@persoft.com (Ed Almasy) writes: >Assuming: > A is a class, with a constructor that requires 3 arguments > B is a class, containing a member of type A > C is a struct, containing a member of type A >My question is: When I create data items of type B or C, where do the >constructor arguments for the member that is of type A come from? Hmm, I rather though the explanation of this in Lippman was quite clear. Essentially you pass arguments to the A constructor from the B and C constructors. The arguments can, of course, be any legal C++ expression involving identifiers that are in scope at the time. This includes the arguments to the B/C constructors. The syntax is as follows: class B { A a_member; public: B(...) :a_member(d, e, f) {.... }; } For instance any of the following would bbe legal: B::B(z) :a_member(1, 2, 3) {...} B::B(z) :a_member(z, z, z+3) {...} B::B(y, z) :a_member(5, y+z, y) {...} and so on. The rules are exactly the same for struct C (because a struct is just a special case of a class). (Note that the sub-constructor arguments go with the *definition* of the outer constructor, not with its declaration in the class definition when the two are different). -- --------------- uunet!tdatirv!sarima (Stanley Friesen)
steve@taumet.com (Stephen Clamage) (02/05/91)
eda@persoft.com (Ed Almasy) writes: >Assuming: > A is a class, with a constructor that requires 3 arguments > B is a class, containing a member of type A > C is a struct, containing a member of type A >My question is: When I create data items of type B or C, where do the >constructor arguments for the member that is of type A come from? A constructor header includes an initialization clause. You may specify initialization of base classes (via their constructors), and of data members. Inside the constructor you specify only assignment, not initialization, of data members. Given class A { public: A(int, int, int); ... }; class B { A a; B(int, int, int); ... }; you would write, for example: B::B(int i, int j, int k) : A(i, j, k) { } This is the same way you pass arguements to base class constructors. This is also the only way you can initialize constant or reference members: class A { ... } a; class C { const int i; A& aref; public: C(); }; C::C() : i(3), aref(a) { } because consider this: C::C() { i = 3; // illegal, i is const aref = ... // aref is uninitialized, so assignment through it // won't do anything good. You can't assign TO a ref. } -- Steve Clamage, TauMetric Corp, steve@taumet.com
steve@taumet.com (Stephen Clamage) (02/05/91)
steve@taumet.com (Stephen Clamage) writes (I wrote): >Given > class A { public: A(int, int, int); }; > class B { A a; B(int, int, int); }; >you would write, for example: > B::B(int i, int j, int k) : A(i, j, k) { ... } >This is the same way you pass arguements to base class constructors. OOPS. I meant to say B::B(int i, int j, int k) : a(i, j, k) If A were a base class of B, you could invoke its constructor as A(i, j, k), using the name of the class. For a data member, you use the name of the member, not its type, in the header. -- Steve Clamage, TauMetric Corp, steve@taumet.com