6

In C++, suppose I have a class Person with following constructor -

Person::Person(const string& nm, const string& id)
{
   name = nm;
   idNum = id; 
}

Now, I also have a subclass of Person called Student with extra data members major and gradYear. Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?

Student::Student(const string& nm, const string& id, const string& maj, int year)
: Person(nm, id){
   major =maj;
   gradYear =year;
}

Can not I define the constructor of Student like this -

Student::Student(const string& nm, const string& id, const string& maj, int year)
{
   Person(nm, id);
   major =maj;
   gradYear =year;
}
sbi
  • 219,715
  • 46
  • 258
  • 445
SegFault
  • 1,024
  • 2
  • 16
  • 25

5 Answers5

11

Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?

Base class constructors are always called before derived class constructors. If you do not call them explicitly in the initialization list, default constructors are called implicitly. If a base class has no default constructor, this doesn't work, so you have to explicitly specify a base class constructor to be called.

It is necessary to invoke base class constructors before the constructors of derived classes because you can access the base class sub-objects from the constructors of derived classes. You can call their public and protected member functions, and for that to succeed, their data members certainly have to be initialized - which is just what base class constructors do.


Can not I define the constructor of Student like this -

Student::Student(const string& nm, const string& id, const string& maj, int year)
{
   Person(nm, id);
   major =maj;
   gradYear =year;
}

No, you can't. Base class constructors are called from the initialization list, before the body of the derived class' constructor is executed. That's just the way the language is defined.
Your syntax creates an unnamed temporary that is immediately discarded.


Note that it is considered good style (and, for some types, also a technical necessity) to also initialize data members in the initialization list.

A very good reason for this is that, in C++, objects have value semantics, they are not references. That is, a variable refers to an actual object, not a reference to an object, and assigning between variables changes actual objects' contents, rather than making them refer to other objects.

Consider this type:

class Student {
  public:
    Student(const std::string& n)
    {
      name = n; // this is bad!
    }
    // ...
  private:
    std::string name;
    // ...
};

That assignment name = n does not assign references to strings, it actually assigns the strings, that is, it invokes the assignment operator which then copies the characters! In order to invoke names's assignment operator, name certainly has to be properly constructed. Therefore, a call to the constructor is silently inserted by the compiler, so that the constructor looks like this:

Student(const std::string& n)
  : name() // therefore 
{
  name = n; // this is bad!
}

Now, this will first create an empty string, just to immediately override it in the very next statement. That's stupid. Therefore, you better initialize all your data members (along with your base classes) in the initialization list:

Student(const std::string& n)
  : name(n) // good!
{
}
Community
  • 1
  • 1
sbi
  • 219,715
  • 46
  • 258
  • 445
  • 1
    One correction: even in a copy constructor, the default base class constructor is called unless you specify otherwise in the initialization lists. The compiler generated copy constructor will call the base class copy constructor, but if you write your own, it's up to you to do so. – James Kanze Oct 18 '11 at 16:29
  • @JamesKanze: Ah, you are right, of course. Sorry for that brainfart! – sbi Oct 18 '11 at 16:31
2

Because you cannot call constructors. Construct initialiser lists are special in several ways, and giving you a means to access the base ctor is one of them. Also, you should always initialise fields in the init list.

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
1

Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?

Is it only necessary if the base class cannot be default constructed. Constructor initialization lists are the only place where one can construct the base classes. Even if you would be able to not do it, why would you? A Student is a Person, so it only makes sense that constructing a Student is an operation that includes constructing a Person.

Can not I define the constructor of Student llike this -

Student::Student(const string& nm, const string& id, const string& maj, int year) { Person(nm, id); major =maj; gradYear =year; }

Well have you tried it? No, you cannot call the base constructor like that. If anything, that would be constructing a temporary unused Person, not the base class.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
1

Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?

The constructor of the base class needs to be called before the constructor of the derived class, so you need to call it in the initialization list of the derived or the compiler will call default constructor for base class before you enter derived class body.

Can not I define the constructor of Student like this -

No You cannot.

The second approach will create a new temporary local object of Person not call Base class constructor for the object being created.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
1

Is it necessary for constructor of the Student class to call the constructor for base class Person in the initializer list, if yes, why?

In short, yes. The derived class constructor will ALWAYS try to call the base class constructor first. If you don't specifically tell it to call your overridden constructor, it will try to call a default constructor (with no params). In your case this will fail as you haven't defined it..

Can not I define the constructor of Student like.....

No, because you can't call a constructor in code like that. And besides, even if you could, your code would fail as the compiler will look for a default constructor for the reasons stated above. If you really wanted to (and I can't think why you would) you could define a default constructor Person::Person(), and then have this:

Student::Student(const string& nm, const string& id, const string& maj, int year) 
{    
    name = nm;     
    idNum = id;
    major =maj;    
    gradYear =year; 
} 
StevieG
  • 8,639
  • 23
  • 31