Home > Net >  objects as class data members using default constructor with and without initializer list
objects as class data members using default constructor with and without initializer list

Time:03-08

for the following program

#include <iostream>
using namespace std;

class university{
private:
    string uni;
public:
    university(){
        cout<<"default constructor of university is invoked"<<endl;
    }
    university(string u){
        uni =u;
        cout<<"parametrized constructor of university is invoked: "<<uni;
    }
};

class student{
private:
    university u;
public:
    student() {
        u = university("ABC");
    }
};

int main()
{
    student s;

    return 0;
}

the output is:

default constructor of university is invoked
parametrized constructor of university is invoked: ABC

but when changing the the constructor of student class to use initializer list like following:

    student(): u(university("ABC")){

    }

the output is:

parametrized constructor of university is invoked: ABC

My question is: for the second case, when the compiler runs the line university u in the private section of student class, does it create an object 'u' of class 'university' and allocate a memory address to it, or does the object get created in the initializer list? if the former, then why didn't it call the default constructor?

for the first case, I have the same question where does the object get created and assigned a memory location.

CodePudding user response:

"Allocating memory" and "assigning memory location" has nothing to do with anything here. You are asking about how objects that are members of another class get constructed. Trying to pull in the subject of memory allocation here only confuses things. Advanced C techniques allow objects to be repeatedly constructed and destroyed "in the same place" (via placement new and explicit destructor invocations). Actual memory locations, and object constructions/destructions, are completely immaterial. They have nothing to do with each other, and it will be helpful if you simply forget everything about memory locations, and focus only on the topic of object construction and destruction. Having said all of that:

An object constructor is responsible for constructing all members of the object. That's the rule. No exceptions. Full stop.

student(): u(university("ABC")){

This will work, but this is also does this in a confusing member. This spells out the following sequence of events: a temporary university object gets constructed, then copy-constructs the actual member of the student class, finally the temporary object gets destroyed. All of this is unnecessary and only serves to muddy the waters. Using a simpler, modern C syntax, this should be:

student(): u{"ABC"}{

This shorter, direct syntax, describes exactly what's going on in a simple, concise manner: the object's constructor constructs all members of this object, invoking u's construct passing to it a character string. The university's "parametrized" constructor gets called. A constructor's member initialization section is nothing more than a simple list: here are my class members, and here are the parameters to their respective constructors. Abracadabra: they're constructed.

student() {

If a constructor does not have a member initialization section, or does not list the object's member in the initialization section, the corresponding class members' default constructors get called.

That's it, that's all there is to it: your class, here the class is called student, has members, and the class's constructor explicitly initializes them, the corresponding constructor gets called, for the class members. If any class member is not listed in the initialization section its default constructor gets called, if the class member does not have a default constructor the resulting code is ill-formed and won't compile.

CodePudding user response:

Members are not initialized in the body of the constructor. They are initialized before the body of the constructor is executed. When you write:

class student{
private:
    university u;
public:
    student() {
        u = university("ABC");
    }
};

Then u = unisversizy("ABC"); is not initialization. As you are not providing an initializer for the u member it will be initialized by calling its default constructor. Then in the constructor university("ABC") creates another object by calling the other constructor and assigns that to u.

PS: In my opinion the term "parametrized constructor" is a very misleading term. The distinction between "parametrized constructor" and a default constructor that is often made in tutorials is just wrong. A default constructor is a constructor that can be called without parameters, hence the following is a default constructor (and it can be called with parameters):

 struct foo {
      foo(int x = 0) {} // a default constructor
                        // is this a parametrized constructor ?!?
 };

CodePudding user response:

Case 1

Here we consider the case where we have:

student() {
        u = university("ABC"); //this is assignment not initialization
    }

When you wrote:

student s; 

These are the effects of the above statement:

  1. Default constructor student::student() of class student is called.
  2. Before entering/executing the body of the default ctor student::student(), the default ctor university::university() of class university is called. As a result, you get the output:
default constructor of university is invoked
  1. Now once the body of university::university() is completely executed, execution of the body of default ctor student::student() is resumed.

  2. While executing the body of student::student() the following statement is encountered:

u = university("ABC");

which is an assignment and not an initialization. Due to the expression univerisity("ABC"), a temporary university object is created using the parameterized constructor of class university and hence you get the output :

parametrized constructor of university is invoked: ABC
  1. The temporary created in the last step is assigned to the data member u.

Case 2

Here we consider the case where we have:

student(): u(university("ABC")){

    }

When you wrote:

student s;

this is what happens:

  1. Default constructor of class student is called.
  2. Before entering the body of the default ctor student::student(), the parameterized constructor university::university(std::string)of class university is called because you have the expression university("ABC") and the data member u is initialized. Note that since the parameterized ctor was called you get the output:
default constructor of university is invoked
  1. Now when the body of the parameterized ctor is completed, execution of the body of default ctor student::student() of class student resumes.

Note

In case 2 of your example, you should change student():u(university("ABC")){} to just:

student(): u("ABC"){

    }
  • Related