[comp.lang.c++] Initializing a Member That is a Class

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