Member initialization lists in composition?

Why is it necessary to use member initialization lists when doing class composition? Is that just what the creators of c++ decided the syntax to be, or is there a specific aspect of composition that requires member initialization lists to be used?
Could you give a code example about what you do mean?
Why is it necessary to use member initialization lists when doing class composition?

It isn't.

But when composing by containment it is the most efficient way to to intialize the contained component class members.

Is that just what the creators of c++ decided the syntax to be, ...

It's the syntax that Stroustrup et al chose for initialization of class member variables (both built-in types and classes) whatever their purpose (for example, I don't see using a std::string member as actually using std::string to form a composite.)

or is there a specific aspect of composition that requires member initialization lists to be used?

Not as such.

If using containment then it might be a requirement (if the a contained class has no default constructor then it will be initialized by necessity in the initializer list) or just the most efficient approach.

Composition means that the component classes have no meaningful independent existence. But it does not necessarily mean it's implemented using containment (though this can be a good approach.)

It is also possible to implement an aggregate using containment or otherwise.

Andy
Last edited on
It isn't.


Are you sure? In bucky's c++ tutorials, he mentioned that they are necessary. And I tried composing without using member initialization lists and it wouldn't compile.

For example, the following code works fine. But as soon as I change it so that 'name' and 'dateOfBirth' are simply set via assignment statements in the body of the People constructor, it does not compile. Why is that?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 #include <iostream>
#include <string>

using namespace std;

class Birthday{

public:
    Birthday(int cmonth, int cday, int cyear){
        month = cmonth;
        day = cday;
        year = cyear;

    }
    void printDate(){
        cout<<month <<"/" <<day <<"/" <<year <<endl;

    }
private:
    int month;
    int day;
    int year;

};

class People{

public:
    People(string cname, Birthday cdateOfBirth)
    :name(cname),
    dateOfBirth(cdateOfBirth)
    {

    }
    void printInfo(){
        cout<<name <<" was born on: ";
        dateOfBirth.printDate();
    }

private:
    string name;
    Birthday dateOfBirth;

};


int main() {

    Birthday birthObject(7,9,97);
    People infoObject("Lenny the Cowboy", birthObject);
    infoObject.printInfo();

}
Why is that?
Because your birthday class does not have default constructor.
andywestken wrote:
(if the a contained class has no default constructor then it will be initialized by necessity in the initializer list)
1. To me neither a date nor a string are significant enough to count as more than a glorified attribute. So this doesn't really stand as a good example of compositions. But...

2. As I said, using the initializer list is the most efficient approach when using containment, but you don't have to use it.

Adding a default constructor and operator= for class Date (which was called Birthday) and initializing member within the body of constructor. (This is the answer to your question "... it does not compile. Why is that?")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <string>

using namespace std;

// no method of class was specific to a Birthday
// so renamed to Date (which is what it is)
//
// Birthday = Date on which you were born
class Date{
public:
    Date()
    : month(0), day(0), year(0) {}
    Date(int cmonth, int cday, int cyear)
    : month(cmonth), day(cday), year(cyear) {}
    Date& operator=(const Date& cdate)
    {
        month = cdate.month;
        day   = cdate.day;
        year  = cdate.year;
        return *this;
    }
    void printDate() const {
        cout << month << "/" << day << "/" << year;
    }

private:
    int month;
    int day;
    int year;
};

// class represent a single Person, not the collective People
class Person{
public:
    Person(const string& cname, const Date& cdateOfBirth)
    {
        name        = cname;
        dateOfBirth = cdateOfBirth;
    }
    void printInfo(){
        cout << name  << " was born on: ";
        dateOfBirth.printDate();
        cout << endl;
    }

private:
    string name;
    Date   dateOfBirth;
};

int main() {
    Date lennysBirthday(7,9,97);
    Person lenny("Lenny the Cowboy", lennysBirthday);
    lenny.printInfo();

    return 0;
}


Andy

PS The explicit Date::operator= is unnecessary here as the compiler generated one can handle the int members ok. But if a deep copy had been necessary, it would have been a different story. So Date could have been just:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Date{
public:
    Date() = default; // C++11 specific
    Date(int cmonth, int cday, int cyear)
    : month(cmonth), day(cday), year(cyear) {}
    void printDate() const {
        cout << month << "/" << day << "/" << year;
    }

private:
    int month;
    int day;
    int year;
};

Last edited on
Dates change, but logically a person's date of birth do not. Therefore, that Person::dateOfBirth should be const, set "on birth" of the Person object.

That is a rather compelling reason to initialize the member variable appropriately. (Of course, one is not forced to add such logical restrictions.)
Actual or admitted date of birth?

Andy
Topic archived. No new replies allowed.