logo codesdope

Subclass


Until now, you have learned about class and objects. In this chapter, you will expand your knowledge to an advanced level.

You are already introduced with inheritance in OOP chapter. So, let's make a subclass of a superclass.

#include <iostream>
#include <string>

using namespace std;

class Student	//base class
{
	string name;
	public:
		string getName()
		{
			return name;
		}
		void setName( string n )
		{
			name = n; 
		}
		void printAbout()
		{
			cout << "I am a student" << endl;
		}
};

class Undergraduate : public Student	//derived class
{
	public:
		void printAbout()
		{
			cout << "I am an Undergraduate" << endl;
		}
};

int main()
{	Student s;
	Undergraduate u;
	s.printAbout();
	u.printAbout();
	return 0;
}
Output
I am a student
I am an Undergraduate

There is no need to explain anything in the 'Student' class.

class Undergraduate : public Student - 'Undergraduate' is the name of a class which is a subclass or derived class of the 'Student' class.

Both classes are having functions with the same name - 'printAbout'. But the definitions (or statements) of the functions are different. These type of functions are called polymorphic functions.
Execution of 'printAbout' from 's' ( object of 'Student' class ) will print "I am a Student." while from 'u' ( object of 'Undergraduate' class ) will print "I am an Undergraduate."
Thus, the objects of each of these classes are calling their respective printAbout function.

So, here Student is a base class or parent class and Undergraduate is a derived class or child class.

Before going further, let's learn more about the protected modifier.

Protected


Any protected member of a class ( variable or function ) can be accessed within that class or its subclass. It cannot be accessed outside that.

Let's see an example.

#include <iostream>
#include <string>

using namespace std;

class Student		//base class
{
	protected:
		string name;
	public:
		void setName( string n )
		{
			name = n; 
		}
};

class Undergraduate : public Student	//derived class
{
	public:
		void printName()
		{
			cout << name << endl;
		}
};

int main()
{	Undergraduate u;
	u.setName("xyz");
	u.printName();
	return 0;
}
Output
xyz

In this example, 'Student' is the parent class and 'Undergraduate' is its child class.
In the 'Student' class, we made name protected. So, it can be accessed directly within its subclass 'Undergraduate'. And we did the same. We accessed the name variable directly in the function printName of its subclass.
Now, let's see what is happening in this example.
We first created an object u of the subclass Undergraduate. Since an object of a subclass can access any of the members of its parent class, so u called the function setName of its parent class with a string parameter "xyz". This string got assigned to the variable 'name' thus making the value of 'name' as "xyz" for the object 'u'.
'u' then called the function 'printName' which printed the value of 'name' i.e., xyz.

Now, let's see what would happen if we try to call a member function of a subclass by the object of the parent class.

#include <iostream>
#include <string>

using namespace std;

class Student		//base class
{
	protected:
		string name;
	public:
		void setName( string n )
		{
			name = n; 
		}
};

class Undergraduate : public Student	//derived class
{
	public:
		void printName()
		{
			cout << name << endl;
		}
};

int main()
{	
	Student s;
	s.setName("xyz");
	s.printName();
	return 0;
}
Output
prog.cpp:29:4: error: no member named 'printName' in 'Student'
        s.printName();
1 error generated.

The above code is giving us error. This is because 's' is an object of the 'Student' class and we are trying to call the function 'printName' of the class 'Undergraduate' by the object of its parent class 'Student' which is invalid.

An object of a subclass can access the members of its superclass ( if not private ) but an object of a superclass can't access the members of its subclasses.

Here is an example showing the same.

#include <iostream>

using namespace std;

class C1
{
	public:
		C1(){}
	protected:
		void m1()
		{
			cout << "This is protected function of superclass" << endl;
		}
};

class C2 : public C1
{
	public:
		C2(){}
		void m2()
		{
			m1();// Since m1 is a protected function of C1, therefore it can be called in its subclass (C2) 
		}
};

int main()
{
	C1 s;
	C2 a;
	a.m2();/* 'a' an object of C2 can access m2( public function of C2)*/
	// s.m2()  Remove this from comment and you will get an error because 's' is an object of superclass can't access function 'm2' of subclass
	// a.m1()  This will also generate an error because m1 is a protected function of C1 and so cannot be called outside C1 or its subclass(C2)
	return 0;
}
Output
This is protected function of superclass

Subclass with constructor


We can normally have constructors for both base and derived class to initialize their respective members. The constructor of the derived class can call the constructor of the base class, but the inverse is not true. Let's see how.

Calling base class constructor having no parameter


If the base class constructor has no parameter, then it will be automatically called by the compiler whenever the derived class constructor will be called, even if we do not explicitly call it.

Look at the following to understand it.

#include <iostream>

using namespace std;

class A
{
	public:
		A()
		{
			cout << "Constructor of A" << endl;
		}
};

class B : public A
{
	public:
		B()
		{
			cout << "Constructor of B" << endl;
		}
};

int main()
{
	B b;
	return 0;
}
Output
Constructor of A
Constructor of B

While calling the constructor of any class, the compiler first automatically calls the constructor of its parent class. This is the reason that while calling the constructor of class B, the compiler first called the constructor of its parent class A and then the constructor of B. Thus when the constructor of 'B' was called, the compiler first called the constructor of 'A' thus printing "Constructor of A" and after that "Constructor of B".

While calling the constructor of any class, the compiler first automatically calls the constructor of its parent class.

Let's see another example where the constructor of the parent class gets automatically called first.

#include <iostream>

using namespace std;

class A
{
	public:
		A()
		{
			cout << "Constructor of A" << endl;
		}
};

class B : public A
{
	public:
		B()
		{
			cout << "Constructor of B" << endl;
		}
};

class C : public B
{
	public:
		C()
		{
			cout << "Constructor of C" << endl;
		}
};

int main()
{
	cout << "Creating object of A :" << endl;
	A a;
	cout << "Creating object of B :" << endl;
	B b;
	cout << "Creating object of C :" << endl;
	C c;
	return 0;
}
Output
Creating object of A :
Constructor of A
Creating object of B :
Constructor of A
Constructor of B
Creating object of C :
Constructor of A
Constructor of B
Constructor of C

Here, when the object of A was created, its constructor was called, printing "Constructor of A".
When the object of B was created, the compiler first called the constructor of its parent class 'A', printing "Constructor of A" and after that printing "Constructor of B".
Similarly, when the constructor of C was called on creating its object, first the constructor of its parent class 'B' was called. On calling the constructor of 'B', the constructor of 'A' got called printing "Constructor of A" followed by "Constructor of B". At last, "Constructor of C" got printed.

Calling parameterized base class constructor


Unlike parent class constructors having no parameter, parameterized parent class constructors are not called automatically while calling its child class constructor.

To call a parent class constructor having some parameter form the constructor of its subclass, we have to use the initialization list of its subclass. Let's see how.

#include <iostream>

using namespace std;

class A
{
	public:
		A( int l )
		{
			cout << "Length : " << l << endl;		
		}
};

class B : public A
{
	public:
		B() : A(20)
		{
			cout << "This is constructor of B" << endl;
		}
};

int main()
{
	B b;
	return 0;
}
Output
Length : 20
This is constructor of B

As in the above example, a parameterized constructor of a class is called from its subclass by writing it in the initialization list with its argument written within brackets.

In this example, when we created an object b of the class B, the constructor 'B' got called. Since the constructor of 'A' is written in its initialization list, the constructor of 'A' got called first with a value 10 passed as its argument.
Thus, its parameter l became equal to 10 and the body of the constructor of 'A' got executed. After that the body of the constructor of 'B' got executed.

Let's see one more example.

#include <iostream>

using namespace std;

class A
{
	int l1;
	public:
	
		A( int z ) : l1(z)
		{
			cout << "l1 : " << l1 << endl;		
		}
};

class B : public A
{
	int l2;
	public:
		B( int x, int y ) : A(x), l2(y)
		{
			cout << "l2 : " << l2 << endl;
		}
};

int main()
{
	B b( 5, 10 );
	return 0;
}
Output
l1 : 5
l2 : 10

In this example, we passed the values 5 and 10 to the constructor of class B while creating its object. So the values 5 and 10 got assigned to x and y respectively.
In the initializer list of the constructor of 'B', the value of 'x' i.e. 5 got passed as the argument of the constructor of 'A' and the value of 'l2' became 10.
Again, the constructor of 'A' first got called making the value of 'l1' as 5. After the body of 'A' got executed, the compiler went back to the body of the constructor of 'B' and executed it.

Let's see one more example of printing the area and perimeter of a rectangle.

#include <iostream>

using namespace std;

class Rectangle
{
	int length;
	int breadth;
	public:
		Rectangle( int l, int b )
		{
			length = l;
			breadth = b;
		}
		int getArea()
		{
			return length * breadth;
		}
		int getPerimeter()
		{
			return 2*( length + breadth );
		}
};

class Square : public Rectangle
{
	public:
		Square( int a ) : Rectangle( a, a )
		{ }
};

int main()
{
	Square s(2);
	int area, p;
	area = s.getArea();
	p = s.getPerimeter();
	cout << "Area : " << area << endl;
	cout << "Perimeter : " << p << endl;
	return 0;
}
Output
Area : 4
Perimeter : 8

We know that square is also a rectangle with the same length and breath. This is what we did in the constructor of 'Square'.
We created an object 's' of class 'Square' and passed 2 at the time of creating it. So, this 2 will be passed to the constructor of class Square. Hence, the value of 'a' will be 2.
In the initialization list of the constructor of 'Square', constructor of its superclass 'Rectangle' is being called with the value of 'a' as 2, thus making the value of both its length and breadth equal to 'a' i.e. 2.
Finally, in the main function, we used the object 's' of the class Square to call two functions of its parent class Rectangle getArea and getPerimeter

Practice everytime you get a chance.
-Bill Monroe

Share what you know
Doubt? Ask question
Close

Welcome.please sign up.

Close

Welcome.please login.