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?
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.
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. 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?")
#include <iostream>
#include <string>
usingnamespace 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;
};