A class can be derived from from another class. Let's say we have a Person class. We can have an Employee class that is derived from it. The Employee class will inherit all the member data variables and the member functions from the Person class. Since an Employee class is derived from a Person class it is a Person class also. This is called upcasting. However a Person may not be an employee so we cannot downcast.
Ex:
#include <iostream>using namespace std ;class Person { public: string firstName ; string lastName ; string getName() { return ( firstName + " " + lastName ) ; }};class Employee : public Person { public: string jobTitle ; void print() { cout << getName() << " " << jobTitle << endl ; }};int main(){ Employee e1 ; //Can access the base class variables e1.firstName = "Alan" ; e1.lastName = "Turing" ; e1.jobTitle = "Programmer" ; e1.print() ; Person p1 ; p1 = e1 ; //Can't do // e1 = p1 ; return 0 ;}
In the above example we have a base class called "Person" and a derived class "Employee". An employee is a person but has more attributes; in this case "jobTitle". It can inherit the attributes and the member functions from the base class.
There is a new access specifier called "protected" . A protected data member can be seen by the derived class but not outside the derived class.
class A1 { public: int x1 ; protected : int x2 ; private : int x3 ;};//B1 is derived from A1class B1 : public A1 { void method1() { x2 = 4 ; //A derived class can access //a protected member //x3 = 5 ; //Cannot access a private member of a base class }};int main(){ A1 A1Object ; B1 B1Object ; int c1 = A1Object.x1 ; //c1 = A1Object.x2 ; //Access issue return 0 ;}
The "protected" scope is not visible outside the class but is visible to the derived class.
Exercise:
1) Modify the firstName and lastName in the Person example above to be protected and "getName" to be public. Comment out the below 2 lines.
e1.firstName = "Alan" ; e1.lastName = "Turing" ;
Compile and run the program.
In addition to data members having access specifier we can specify an access specifier in the derived class and that tells us what the access ( modified ) would be in the derived class for the base class for someone looking at it from outside. One easy way to remember what the access means is to think of the access as it applies to the public and protected members of the base class. Public inheritance means that the public and protected members of the base class stay as it is. Protected inheritance means that the public and protected members of the base class become protected and private inheritance means the public and protected members of the base class become private.
The concept is somewhat confusing in the beginning and we need to look at some examples .
class Base { public: int m_public; private: int m_private; protected: int m_protected;};class Pub: public Base // note: public inheritance{// Public inheritance means:// Public inherited members stay public (so m_public is treated as public)// Protected inherited members stay protected (so m_protected is treated as protected)// Private inherited members stay inaccessible (so m_private is inaccessible)public: Pub() { m_public = 1; // okay: m_public was inherited as public //m_private = 2; // not okay: m_private is inaccessible from derived class m_protected = 3; // okay: m_protected was inherited as protected }};int main(){// Outside access uses the access specifiers of the class being accessed. Base base; base.m_public = 1; // okay: m_public is public in Base//base.m_private = 2; // not okay: m_private is private in Base//base.m_protected = 3; // not okay: m_protected is protected in Base Pub pub; pub.m_public = 1; // okay: m_public is public in Pub//pub.m_private = 2; // not okay: m_private is inaccessible in Pub//pub.m_protected = 3; //}
Protected Inheritance
class Base {public: int m_public;private: int m_private;protected: int m_protected;};class Protect: protected Base // note: private inheritance{ // Protected inheritance means: // Public inherited members become protected (so m_public is treated as private) // Protected inherited members become protected (so m_protected is treated as protected) // Private inherited members stay inaccessible (so m_private is inaccessible)public: Protect() { m_public = 1; // okay: m_public is now protected in Protect //m_private = 2; // not okay: derived classes can't access private members in the base class m_protected = 3; // okay: m_protected is protected in Protect }};class Derived : public Protect { public: Derived() { m_protected = 5 ; }};int main(){ // Outside access uses the access specifiers of the class being accessed. // In this case, the access specifiers of base. Base base; base.m_public = 1; // okay: m_public is public in Base //base.m_private = 2; // not okay: m_private is private in Base //base.m_protected = 3; // not okay: m_protected is protected in Base Protect pri; //pri.m_public = 1; // not okay: m_public is now protected in Protect //pri.m_private = 2; // not okay: m_private is inaccessible in Protect //pri.m_protected = 3; // not okay: m_protected is now protected in Protect}
Private Inheritance
class Base {public: int m_public;private: int m_private;protected: int m_protected;};class Pri: private Base // note: private inheritance{ // Private inheritance means: // Public inherited members become private (so m_public is treated as private) // Protected inherited members become private (so m_protected is treated as private) // Private inherited members stay inaccessible (so m_private is inaccessible)public: Pri() { m_public = 1; // okay: m_public is now private in Pri // m_private = 2; // not okay: derived classes can't access private members in the base class m_protected = 3; // okay: m_protected is now private in Pri }};class Derived : public Pri { public: Derived() { //Compiler error //m_protected = 5 ; }};int main(){ // Outside access uses the access specifiers of the class being accessed. // In this case, the access specifiers of base. Base base; base.m_public = 1; // okay: m_public is public in Base //base.m_private = 2; // not okay: m_private is private in Base //base.m_protected = 3; // not okay: m_protected is protected in Base Pri pri; // pri.m_public = 1; // not okay: m_public is now private in Pri //pri.m_private = 2; // not okay: m_private is inaccessible in Pri //pri.m_protected = 3; // not okay: m_protected is now private in Pri}
Exercise
Find all the access errors in the below program.
File: "ex1.cpp"
class Base {public: int m_public; Base() { m_private = 3 ; }private: int m_private ;protected: int m_protected ;};class Derived: public Base { protected: int p_var1 ; private: int p_var2 ; public: int p_var3 ; Derived() { m_private = 4 ; m_protected = 5 ; p_var2 = 6 ; }};class Derived1 : private Derived { public: Derived1() { p_var1 = 4 ; p_var2 = 5 ; m_public = 6 ; }};int main(){ Base baseObject ; Derived derivedObject ; Derived1 derived1Object ; baseObject.m_public = 1; baseObject.m_protected = 2 ; derivedObject.m_public = 1 ; derived1Object.m_public = 1 ; derived1Object.p_var3 = 3 ;}
If the base class has a constructor then how can we call it when constructing an object of the derived class ? We can use initialization lists.
#include <iostream>using namespace std ;class Person { public: string firstName ; string lastName ; string getName() { return ( firstName + " " + lastName ) ; } Person( string firstNameP, string lastNameP ) { firstName = firstNameP ; lastName = lastNameP ; }};class Employee : public Person { public: string jobTitle ; Employee( string firstNameP, string lastNameP, string jobTitleP) :Person(firstNameP, lastNameP ) { jobTitle = jobTitleP ; } void print() { cout << getName() << " " << jobTitle << endl ; }};int main(){ Employee e1( "Alan" , "Turing" , "Programmer" ) ; e1.print() ; return 0 ;}
Exercise
Modify the below program so that the constant id in the class Person is set by modifying the constructors of both the Person and Employee class.
File: "ex2.cpp"
#include <iostream>using namespace std ;class Person { public: string firstName ; string lastName ; const int id ; string getName() { return ( firstName + " " + lastName ) ; } Person( string firstNameP, string lastNameP ) { firstName = firstNameP ; lastName = lastNameP ; }};class Employee : public Person { public: string jobTitle ; Employee( string firstNameP, string lastNameP, string jobTitleP) :Person(firstNameP, lastNameP ) { jobTitle = jobTitleP ; } void print() { cout << getName() << " " << jobTitle << " " << id << endl ; }};int main(){ Employee e1( "Alan" , "Turing" , "Programmer" , 1) ; e1.print() ; return 0 ;}
File: "ex3.cpp"
Complete the to do section by providing a constructor for the Manager class and the same constructor should also use initialization list to set the value for "noOfPeopleManaged" .
#include <iostream>using namespace std ;class Person { public: string firstName ; string lastName ; const int id ; string getName() { return ( firstName + " " + lastName ) ; } Person( string firstNameP, string lastNameP, int idP ) : id(idP) { firstName = firstNameP ; lastName = lastNameP ; }};class Employee : public Person { public: string jobTitle ; Employee( string firstNameP, string lastNameP, string jobTitleP, int idP) :Person(firstNameP, lastNameP , idP ) { jobTitle = jobTitleP ; } void print() { cout << getName() << " " << jobTitle << " " << id << endl ; }};class Manager : public Employee { public : int noOfPeopleManaged ; //TO DO //Add a constructo . Set the value for noOfPeopleManaged
{
} void print() { cout << getName() << " " << jobTitle << " " << id << " " << noOfPeopleManaged << endl ; }};int main(){ Manager m1( "Alan" , "Turing" , "Programmer" , 1, 5 ) ; m1.print() ; return 0 ;}
Polymorphism means to take on many forms. In Computer Science it means if we convert a derived object to a base class object and call a member function that has been defined in both the base and derived classes then the correct ( derived class's object ) method will be called.
Ex:
#include <iostream>using namespace std ;//----------------------------------class class1 { public: virtual void print() { cout << "Class class1" << endl ; }};//----------------------------------class class2 : public class1 { public: void print() { cout << "Class class2" << endl ; }};class class3 : public class2 { public: void print() { cout << "Class class3" << endl ; }};//----------------------------------int main(){ class1 class1Obj ; class2 class2Obj ; class3 class3Obj ; //Polymorphism only works with pointers class1Obj = class2Obj ; class1Obj.print() ; class1Obj = class3Obj ; class1Obj.print() ; cout << "----------------" << endl ; class1* class1ObjPtr ; class1ObjPtr = new class2() ; class1ObjPtr->print() ; class1ObjPtr = new class3() ; class1ObjPtr->print() ; return ( 0 ) ;}
Output:
[amittal@hills Inheritance]$ ./a.out
Class class1
Class class1
Class class2
Class class3
In the above code we first assign objects to the base class . The immediate derived class class2 object is assigned to the base class. We use the keyword "virtual" to indicate that we are interested in this function to be used in a polymorphic manner. We have a base class "class1" and then a derived class "class2" and another class "class3" derived from "class2" . If we use objects then the behavior is as before. We must use pointers or references in order to achieve polymorphism.
class1Obj = class2Obj ;
class1Obj.print() ;
We assign "class2Obj" to "class1Obj" and then call the "print" function of "class1Obj". This ends up calling the "print" function of "class1" and not "class2" . Using pointers we can see that the print function of the derived class got called even though the object being used was the base object. We need to do couple of things in order to make polymorphism happen.
1) Use the virtual keyword in the base class. ( Why )
2) Use pointers
3) Use functions in the classes with the same signature.
Let us take out the "virtual" and keyword and observe the behavior.
File: "poly2.cpp"
#include <iostream>using namespace std ;//----------------------------------class class1 { public: void print() { cout << "Class class1" << endl ; }};//----------------------------------class class2 : public class1 { public: void print() { cout << "Class class2" << endl ; }};class class3 : public class2 { public: void print() { cout << "Class class3" << endl ; }};//----------------------------------int main(){ class1 class1Obj ; class2 class2Obj ; class3 class3Obj ; //Polymorphism only works with pointers class1Obj = class2Obj ; class1Obj.print() ; class1Obj = class3Obj ; class1Obj.print() ; cout << "----------------" << endl ; class1* class1ObjPtr ; class1ObjPtr = new class2() ; class1ObjPtr->print() ; class1ObjPtr = new class3() ; class1ObjPtr->print() ; return ( 0 ) ;}
Output:
$ ./a.exe
Class class1
Class class1
----------------
Class class1
Class class1
What happens if the derived class does not contain the function. In that case the base function gets called. If the immediate base class does not have the function then we move one hierarchy up.
File:
"poly3.cpp"
#include <iostream>using namespace std ;//----------------------------------class class1 { public: virtual void print() { cout << "Class class1" << endl ; }};//----------------------------------class class2 : public class1 { public: void print() { cout << "Class class2" << endl ; }};class class3 : public class2 { public:};class class4 : public class3 { public:};//----------------------------------int main(){ cout << "----------------" << endl ; class1* class1ObjPtr ; class1ObjPtr = new class3() ; class1ObjPtr->print() ; class1ObjPtr = new class4() ; class1ObjPtr->print() ; return ( 0 ) ;}
Output:
$ g++ poly3.cpp ; ./a.exe
----------------
Class class2
Class class2
File: "poly4.cpp"
#include <iostream>using namespace std ;//----------------------------------class class1 { public: void print() { cout << "Class class1" << endl ; }};//----------------------------------class class2 : public class1 { public: void print() { cout << "Class class2" << endl ; }};class class3 : public class2 { public: virtual void print() { cout << "Class class3" << endl ; }};class class4 : public class3 { public: void print() { cout << "Class class4" << endl ; }};//----------------------------------int main(){ cout << "----------------" << endl ; class1* class1ObjPtr ; class1ObjPtr = new class2() ; //No polymorphism here class1ObjPtr->print() ; class3* class3ObjPtr ; class3ObjPtr = new class4() ; class3ObjPtr->print() ; return ( 0 ) ;}
$ g++ poly4.cpp ; ./a.exe
----------------
Class class1
Class class4
The above class has a hierarchy of the form:
class 1
class 2
class 3
virtual
class 4
All 4 classes have a method "print()" with the same signature but the polymorphism only start at "class3" and then downwards. It does not matter if the classes below have the virtual keyword or not.
Why did they design the language as such ? Why not let all the derived class practice polymorphism without the "virtual" keyword. It has to do with efficiency. First of all the machine language does not have any idea of classes, inheritance and polymorphism. The machine language does know about functions and addresses.
File: "poly3a.cpp"
#include <iostream>using namespace std ;//----------------------------------class class1 { public: void print() { cout << "Class class1" << endl ; }};//----------------------------------class class2 : public class1 { public: void print() { cout << "Class class2" << endl ; }};class class3 : public class2 { public:};class class4 : public class3 { public:};//----------------------------------int main(){ cout << "----------------" << endl ; class3* class3ObjPtr ; class3ObjPtr = new class3() ; class3ObjPtr->print() ; class4* class4ObjPtr ; class3ObjPtr = new class4() ; class3ObjPtr->print() ; return ( 0 ) ;}
$ ./a.exe
----------------
Class class2
Class class2
If we don't use the virtual keyword then the outcome of a class's method is fixed as we can see in the above example. The problem appears when the virtual keyword is used and a class is up cast to a base class and now the behavior is different depending on what the original object was.
Let's take a look at the below program:
File: "poly5.cpp"
#include <iostream>using namespace std ;//----------------------------------class class1 { public: virtual void print() { cout << "Class class1" << endl ; } virtual void method1() { cout << "Class1:method1" << endl ; }};//----------------------------------class class2 : public class1 { public: void print() { cout << "Class class2" << endl ; }};int main(){ cout << "----------------" << endl ; class1* class1ObjPtr ; class1ObjPtr = new class2() ; class1ObjPtr->print() ; return ( 0 ) ;}
Now how does C++ "implement" polymorphism. Each class keeps a pointer to a table. In this table we have a mapping. For class1 and class 2 it will be :
class 1 ---> class1::print
method1
class 2 --> class2::print
class1::method1
If we have an object of class 1 ( original object ) then we call the 2 methods of class 1 but if we have an original object of class 2 then the mapping is such that the print method of class2 will be called because it was virtual in class1 . However the method1 will be that of the class 1 because class 2 simply does not have an implementation for method1. This logic comes into play when we store the class2 object in a pointer of class 1. We might have to call some methods in the same original class and some methods in the base class. This extra work of storing this mapping table can be avoided if we are not using polymorphism. The virtual keyword introduces this table mapping and pointer in each class in the hierarchy.
class1ObjPtr = new class2() ;
In the above we assign the class2 object to class1 . However the classObjPtr has a reference to the virtual table that is still of class2. Each class in the hierarchy has an additional member that is the table mapping .
Sometimes we are in the derived class virtual method but we also need to call the base method. We can do that with the syntax:
BaseClass::method
File: "poly6.cpp"
#include <iostream>using namespace std ;//----------------------------------class class1 { public: virtual void print() { cout << "class1::print" << endl ; }};//----------------------------------class class2 : public class1 { public: void print() { class1::print() ; cout << "class2::print" << endl ; }};int main(){ cout << "----------------" << endl ; class1* class1ObjPtr ; class1ObjPtr = new class2() ; class1ObjPtr->print() ; return ( 0 ) ;}
Output:
$ g++ poly6.cpp ; ./a.exe
----------------
class1::print
class2::print
Exercise:
1) Modify the below program "TO DO" section so that the base class print is also called and then compile and run the program.
File: "ex4.cpp"
#include <iostream>using namespace std ;//----------------------------------class Person { public: string firstName ; string lastName ; const int id ; string getName() { return ( firstName + " " + lastName ) ; } Person( string firstNameP, string lastNameP, int idP ) : id(idP) { firstName = firstNameP ; lastName = lastNameP ; } virtual void print() { cout <<"Name:" << getName() << " " << "Id:" << id << " " ; }};//----------------------------------class Employee : public Person { public: string jobTitle ; Employee( string firstNameP, string lastNameP, string jobTitleP, int idP) :Person(firstNameP, lastNameP , idP ) { jobTitle = jobTitleP ; } void print() { //TO DO cout << "Job Title:" << jobTitle << " " << endl ; }};//----------------------------------int main(){ Employee e1( "Alan" , "Turing" , "Programmer" , 1) ; e1.print() ; return ( 0 ) ;}//----------------------------------
Output:
$ g++ ex4.cpp ; ./a.exe
Name:Alan Turing Id:1Job Title:Programmer
2)
Does the below program compile and if so what is the output ? Explain the output.
#include <iostream>using namespace std ;//----------------------------------class class1 { public: void print() { cout << "class1::print" << endl ; }};//----------------------------------class class2 : public class1 { public: virtual void print() { class1::print() ; cout << "class2::print" << endl ; }};class class3 : public class2 { public: void print() { class1::print() ; cout << "class3::print" << endl ; }};int main(){ cout << "----------------" << endl ; class1* class1ObjPtr ; class2* class2ObjPtr ; class1ObjPtr = new class2() ; class1ObjPtr->print() ; class1ObjPtr = new class3() ; class1ObjPtr->print() ; class2ObjPtr = new class3() ; class2ObjPtr->print() ; return ( 0 ) ;}
What's a virtual constructor. Well virtual means that we create an object of certain class and assign it to base class. But when creating class we already specify the exact class to create. The concept of virtual constructor does not make sense. If the class has a base class then the base class constructor gets called.
File: "poly7.cpp"
#include <iostream>using namespace std ;//----------------------------------class Person { public: string firstName ; string lastName ; const int id ; string getName() { return ( firstName + " " + lastName ) ; } Person( string firstNameP, string lastNameP, int idP ) : id(idP) { firstName = firstNameP ; lastName = lastNameP ; } virtual void print() { cout <<"Name:" << getName() << " " << "Id:" << id << " " ; } virtual ~Person() { cout << "Person Destructor." << endl ; }};//----------------------------------class Employee : public Person { public: string jobTitle ; Employee( string firstNameP, string lastNameP, string jobTitleP, int idP) :Person(firstNameP, lastNameP , idP ) { jobTitle = jobTitleP ; } void print() { //TO DO Person::print() ; cout << "Job Title:" << jobTitle << " " << endl ; } virtual ~Employee() { cout << "Employee Destructor." << endl ; }};//----------------------------------int main(){ Person* e1 = new Employee( "Alan" , "Turing" , "Programmer" , 1) ; e1->print() ; delete e1 ; return ( 0 ) ;}//----------------------------------
Output:
$ g++ poly7.cpp ; ./a.exe
Name:Alan Turing Id:1 Job Title:Programmer
Employee Destructor.
Person Destructor.
We create an object of "Employee" that is assigned to the "Person" class. Upon deleting the Person class the virtual Employee destructor gets called first and then the "Person" destructor ( base class ) destructor gets called. Any time we have a virtual function or are using pointers to the base class having derived class objects we should use a virtual destructor. We create the base class object and then the derived class object. The destruction is done in the reverse order. We destroy the derived class object and then the base class object. Just as the base class constructor gets called first and then the derived class automatically the virtual destructor calls the derived class and the base class destructor automatically.
File: "poly8.cpp"
#include <iostream>using namespace std ;//----------------------------------class Person { public: string firstName ; string lastName ; const int id ; string getName() { return ( firstName + " " + lastName ) ; } Person( string firstNameP, string lastNameP, int idP ) : id(idP) { cout << "Person Constuctor." << endl ; firstName = firstNameP ; lastName = lastNameP ; } virtual void print() { cout <<"Name:" << getName() << " " << "Id:" << id << " " ; } virtual ~Person() { cout << "Person Destructor." << endl ; }};//----------------------------------class Employee : public Person { public: string jobTitle ; Employee( string firstNameP, string lastNameP, string jobTitleP, int idP) :Person(firstNameP, lastNameP , idP ) { cout << "Employee Constuctor." << endl ; jobTitle = jobTitleP ; } void print() { //TO DO Person::print() ; cout << "Job Title:" << jobTitle << " " << endl ; } virtual ~Employee() { cout << "Employee Destructor." << endl ; }};//----------------------------------int main(){ Person* e1 = new Employee( "Alan" , "Turing" , "Programmer" , 1) ; e1->print() ; delete e1 ; return ( 0 ) ;}//----------------------------------
Output:
$ g++ poly8.cpp ; ./a.exe
Person Constuctor.
Employee Constuctor.
Name:Alan Turing Id:1 Job Title:Programmer
Employee Destructor.
Person Destructor.
Exercise:
5)
Correct the compiler errors in the below program and modify it to produce the output shown below the program.
#include <iostream>using namespace std ;//----------------------------------class A1 { public: A1() { cout << "A1 Constructor" << endl ; } protected: ~A1() { cout << "A1 Destructor" << endl ; }};//----------------------------------class B1 : public A1 { public: B1() { cout << "B1 Constructor" << endl ; } ~B1() { cout << "B1 Destructor" << endl ; }};int main(){ A1* a1Object = new B1() ; delete a1Object ; return ( 0 ) ;}//----------------------------------
$ g++ ex5.cpp ; ./a.exe
A1 Constructor
B1 Constructor
B1 Destructor
A1 Destructor
6)
What's wrong with the following program ? Correct the error .
#include <iostream>using namespace std ;class class1 { public: int* basePtr = NULL ; void print() { cout << "class1::print" << endl ; } class1() { cout << "class1 constructor" << endl ; basePtr = new int[10] ; } ~class1() { cout << "class1 destructor" << endl ; delete[] basePtr ; }};//----------------------------------class class2 : public class1 { public: public: int* derivedPtr = NULL ; void print() { cout << "class2::print" << endl ; } class2() { cout << "class2 constructor" << endl ; derivedPtr = new int[10] ; } ~class2() { cout << "class2 destructor" << endl ; delete[] derivedPtr ; }};class class3 : public class2 { public: void print() { class1::print() ; cout << "class3::print" << endl ; }};int main(){ cout << "----------------" << endl ; class1* class1ObjPtr ; class2* class2ObjPtr ; class1ObjPtr = new class2() ; delete class1ObjPtr ; return ( 0 ) ;}//----------------------------------
An abstract class is a class that cannot be instantiated and contains at least one pure virtual function.
File: "poly9.cpp"
#include <iostream>using namespace std ;//----------------------------------class A1 { public: virtual void method1() = 0 ;};//----------------------------------class B1 : public A1 { public: void method1() { cout << "B1::method1" << endl ; }} ;//----------------------------------int main(){ //Compiler error //A1 a1Object ; B1 b1Object ; b1Object.method1() ; A1* a1Object ; a1Object = new B1() ; a1Object->method1() ; return ( 0 ) ;}//----------------------------------
$ ./a.exe
B1::method1
B1::method1
Class "A1" has a pure virtual method named "method1" that has no body. We cannot create instances of the class "A1". We can create a derived class that provides an implementation of the pure virtual method. Class "A1" is called an abstract class. Abstract classes are also known as interfaces as they allow us to specify methods that don't have a body. What happens if the derived class doesn't have a body for the member function.
File: "poly10.cpp"
#include <iostream>using namespace std ;//----------------------------------class A1 { public: virtual void method1() = 0 ;};//----------------------------------class B1 : public A1 { public:} ;//----------------------------------int main(){ //Compiler error //A1 a1Object ; B1 b1Object ; b1Object.method1() ; A1* a1Object ; a1Object = new B1() ; a1Object->method1() ; return ( 0 ) ;}//----------------------------------
We get compiler errors in the above. A derived class that does not implement the pure virtual function is also an abstract class and we cannot create instances of it.
File: "myvect.cpp"
#include <iostream>using namespace std ;//----------------------------------class mylist { public: virtual int getItem(int index) = 0 ; virtual int getSize() = 0 ; void print() { for( int i1=0 ; i1 < getSize() ; i1++ ) { cout << getItem( i1 ) << " " ; } cout << endl ; }};class myvector : public mylist { public: int* ptr ; int size ; myvector( int sizeP ) { ptr = new int[sizeP] ; size = sizeP ; for( int i1=0 ; i1 < size ; i1++ ) { ptr[i1] = i1+1 ; } } ~myvector() { delete[] ptr ; } int getItem(int index) { return ( ptr[index] ) ; } int getSize() { return size ; }};int main (){ myvector myvectorObj(10) ; myvectorObj.print() ; return(0);}
Output:
$ ./a.exe
1 2 3 4 5 6 7 8 9 10
Exercise
6)
What does the following print ?
#include <iostream>using namespace std ;//----------------------------------class A1 { public: virtual void method1() = 0 ; void method2() { cout << "A1::method2" << endl ; }};//----------------------------------class B1 : public A1 { public: void method1() { cout << "B1::method1" << endl ; method2() ; }} ;//----------------------------------int main(){ A1* a1Object ; a1Object = new B1() ; a1Object->method1() ; return ( 0 ) ;}//----------------------------------
File: "m1.cpp"
#include <iostream>using namespace std ;class classA { public:};//----------------------------------class classB { public:};class classC : public classA, public classB {};int main(){ classC classCObject ; return ( 0 ) ;}//----------------------------------
In the above file we can see the "classC" inherits from 2 classes "classA" and "classB" . Sometimes this can create a problem.
File: "m2.cpp"
#include <iostream>using namespace std ;class classA { public: int var1 ;};//----------------------------------class classB { public: int var1 ;};class classC : public classA, public classB { public: void method1() { var1 = 10 ; }};int main(){ classC classCObject ; return ( 0 ) ;}//----------------------------------
Output:
$ g++ m2.cpp
m2.cpp: In member function ‘void classC::method1()’:
m2.cpp:26:10: error: reference to ‘var1’ is ambiguous
26 | var1 = 10 ;
Both the base classes have a variable "var1" and this creates the ambiguity.
#include <iostream>using namespace std ;class classA { public: int var1 ;};//----------------------------------class classB { public: int var1 ;};class classC : public classA, public classB { public: void method1() { classA::var1 = 10 ; classB::var1 = 10 ; }};int main(){ classC classCObject ; return ( 0 ) ;}//----------------------------------
We can resolve the problem by specifying which class the variable "var1" belongs to with the syntax:
classA::var1 = 10 ;
How about if the base classes have constructors ? We can use initialization lists.
#include <iostream>using namespace std ;class classA { public: int var1 ; classA( int var1P ) { var1 = var1P ; }};//----------------------------------class classB { public: int var1 ; classB( int var1P ) { var1 = var1P ; }};class classC : public classA, public classB { public: classC( int var1P ) : classA( var1P ) , classB( var1P ) { }};int main(){ classC classCObject(10) ; return ( 0 ) ;}//----------------------------------
A problem occurs when we have a structure of the form:
A
B C
D
The class D derives from classes B and C and both B and C derive from A .
File: "m5.cpp"
#include <iostream>using namespace std ;class classA { public: classA() { cout << "Constructor for class A" << endl ; }};//----------------------------------class classB : public classA { public: classB( ) { cout << "Constructor for class B" << endl ; }};//----------------------------------class classC : public classA { public: classC( ) { cout << "Constructor for class C" << endl ; }};//----------------------------------class classD : public classB, public classC { public: classD( ) { cout << "Constructor for class D" << endl ; }};//----------------------------------int main(){ classD classDObject ; return ( 0 ) ;}//----------------------------------
Output:
$ g++ m5.cpp ; ./a.exe
Constructor for class A
Constructor for class B
Constructor for class A
Constructor for class C
Constructor for class D
The constructor for class A is getting called twice. Each class B and C are going to have their own copy of class A . We want only 1 copy of class A. This is where virtual inheritance comes in.
File: "m6.cpp"
#include <iostream> using namespace std ; class classA { public: classA() { cout << "Constructor for class A" << endl ; } }; //---------------------------------- class classB : virtual public classA { public: classB( ) { cout << "Constructor for class B" << endl ; } }; //---------------------------------- class classC : virtual public classA { public: classC( ) { cout << "Constructor for class C" << endl ; } }; //---------------------------------- class classD : public classB, public classC { public: classD( ) { cout << "Constructor for class D" << endl ; } }; //---------------------------------- int main() { classD classDObject ; return ( 0 ) ; } //----------------------------------
Output:
Constructor for class A
Constructor for class B
Constructor for class C
Constructor for class D
What happens if class A has a constructor that has an argument. In that case we need to call it from the grand child class D.
File: "m7.cpp"
#include <iostream> using namespace std ; /* A */ class classA { public: classA(int x1) { cout << "Constructor for class A" << endl ; } }; //---------------------------------- class classB : virtual public classA { public: classB(int y1 ) : classA( y1 ) { cout << "Constructor for class B" << endl ; } }; //---------------------------------- class classC : virtual public classA { public: classC(int z1 ) : classA( z1 ) { cout << "Constructor for class C" << endl ; } }; //---------------------------------- class classD : public classB, public classC { public: classD(int a1 ) : classB( a1 ) , classC( a1 ) , classA( a1 ) { cout << "Constructor for class D" << endl ; } }; //---------------------------------- int main() { classD classDObject( 5 ) ; return ( 0 ) ; } //----------------------------------
A class can define another class inside it.
File: "nested1.cpp"
#include <iostream>using namespace std ;class A { public: int var1 ; class B { private: int num; public: void setData(int n) { num = n; //compiler error cannot access outer //variables //var1 = 5 ; } void printData() { cout<<"The number is "<<num; } };};int main(){ A::B objectOfClassB ; objectOfClassB.setData(5) ; objectOfClassB.printData() ; return 0 ;}
The class B does not have automatic access to A . It is a class by itself with really no connection to A . We can create objects of it as we have done in the "main" function.
File: "nested2.cpp"
#include <iostream>using namespace std ;//----------------------------------class mylist { public: virtual int getItem(int index) = 0 ; virtual int getSize() = 0 ; void print() { for( int i1=0 ; i1 < getSize() ; i1++ ) { cout << getItem( i1 ) << " " ; } cout << endl ; }};class myIterator { public: virtual int getNext() = 0 ;};class myvector : public mylist { public: int* ptr ; int size ; myvector( int sizeP ) { ptr = new int[sizeP] ; size = sizeP ; for( int i1=0 ; i1 < size ; i1++ ) { ptr[i1] = i1+1 ; } } ~myvector() { delete[] ptr ; } int getItem(int index) { return ( ptr[index] ) ; } int getSize() { return size ; } myIterator* getIterator() { iterator1* iterator1Ptr = new iterator1( *this ) ; return iterator1Ptr ; } class iterator1 : public myIterator { public: int index = 0 ; myvector& refVector ; iterator1( myvector& refVectorP ) : refVector( refVectorP ) { } int getNext() { index++ ; return ( refVector.getItem( index -1 ) ); } };};int main (){ myvector myvectorObj(10) ; myvectorObj.print() ; myIterator* iteratorPtr = myvectorObj.getIterator() ; cout << iteratorPtr->getNext() << " " << iteratorPtr->getNext() << endl ; return(0);}
Access issues in nested classes. The 2 examples below show how access works in nested classes.
#include<iostream>using namespace std;/* start of Enclosing class declaration */class Enclosing {private: int x; /* start of Nested class declaration */ class Nested { int y; void NestedFunc(Enclosing *e) { cout<<e->x; // works fine: nested class can access // private members of Enclosing class } }; // declaration Nested class ends here}; // declaration Enclosing class ends hereint main(){}
#include<iostream>using namespace std;/* start of Enclosing class declaration */class Enclosing { int x; /* start of Nested class declaration */ class Nested { int y; }; // declaration Nested class ends here void EnclosingFun(Nested *n) { cout<<n->y; // Compiler Error: y is private in Nested }}; // declaration Enclosing class ends hereint main(){}
Ex1:
What does the following program output ?
#include <iostream>#include <vector>using namespace std;//--------------------------------------------------------------------------------------------class base1 { public: void function1() { cout << "Inside base1 class." << endl ; }};class derived1 : public base1 { public: virtual void function1() { cout << "Inside derived1 class." << endl ; }};class derived2 : public derived1 { public: void function1() { cout << "Inside derived2 class." << endl ; }};class derived3 : public derived2 { public:};class derived4 : public derived3 { public: void function1() { cout << "Inside derived4 class." << endl ; }};//--------------------------------------------------------------------------------------------int main(){ base1* ptrBase = new derived1() ; ptrBase->function1() ; derived1* ptrDerived1 = new derived2() ; ptrDerived1->function1() ; derived2* ptrDerived2 = new derived4() ; ptrDerived2->function1() ; ptrDerived2 = new derived3() ; ptrDerived2->function1() ; return 0;}
Ex2:
How do you resolve the following errors ? Do not give more access than necessary to resolve the error.
#include <iostream>using namespace std ;class A { private: int x1 = 4 ; protected: void function1() { }};class B { private : void function1() { x1 = 5 ; }};class Derived: public A, public B { protected: void function1() { A::function1() ; B::function1() ; }};int main(){ Derived d1 ; d1.function1() ; return ( 1) ;}
#include <iostream>using namespace std ;class A { private: int x1 = 4 ; protected: A( int x1P) { x1 = x1P ; }};class B { int y1 ; public: B( int y1P) { y1 = y1P ; }};class C : public A { B objectB ; public : //TO DO Write the constructor};int main(){ //10 is used to initialize innerObject B and 11 is used to //initialize base class A C object(10 , 11 ) ; return ( 1) ;
}
Sol 1
Inside base1 class.
Inside derived2 class.
Inside derived4 class.
Inside derived2 class.
Sol2
See attached multi1.cpp