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:
- Default constructor
student::student()
of classstudent
is called. - Before entering/executing the body of the default ctor
student::student()
, the default ctoruniversity::university()
of classuniversity
is called. As a result, you get the output:
default constructor of university is invoked
Now once the body of
university::university()
is completely executed, execution of the body of default ctorstudent::student()
is resumed.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
- 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:
- Default constructor of class
student
is called. - Before entering the body of the default ctor
student::student()
, the parameterized constructoruniversity::university(std::string)
of classuniversity
is called because you have the expressionuniversity("ABC")
and the data memberu
is initialized. Note that since the parameterized ctor was called you get the output:
default constructor of university is invoked
- Now when the body of the parameterized ctor is completed, execution of the body of default ctor
student::student()
of classstudent
resumes.
Note
In case 2 of your example, you should change student():u(university("ABC")){}
to just:
student(): u("ABC"){
}