 Welcome back to this session on computer programming in C++. Today we are going to talk about advanced operations with inheritance. Here is a recap of what we studied in the last lecture. We saw how member functions of a base class can be redefined in a derived class. We saw how methods of a base class can be accessed inside derived classes. We studied about constructors, destructors and assignment operators in the context of inheritance. In this lecture, we are going to look at a bit more closely about how objects of base and derived classes are related, what can and cannot be done with them. We will also look at objects of classes with pointers and references and we will look at some special kinds of inheritance called multiple inheritance and diamond inheritance. Much of this lecture is motivated by the treatment in the book and introduction to programming through C++ by Aviram G. Ranade published by Macra Hill Education 2014. Some of the examples that I am going to talk about are taken from this book. So let us talk about objects of base and derived class. So here is a base class which we have seen earlier in our earlier lectures, it is about a bank account and here is a derived class, a savings class which is talking about a savings bank account and here is a main program in which I have instantiated objects of the base class, initialized data members, instantiated an object of the savings class, initialized its data members, printed out the values of these data members and over here I have tried to assign an object of the derived class to an object of the base class. Now we saw in the last lecture when we talked about assignment operators that this is actually fine because an object of the base class is on the left hand side and an object of the derived class is on the right hand side of the assignment operator and this object of the derived class can also be thought of as an object of the base class and so this assignment is fine. We also saw in the last lecture how we can see that this is a perfectly fine assignment by going back to the semantics of the operator equal to method in the base class B. So what is the output that we expect here from these two statements and these two statements, well here it will print out the values of id and balance for the object B. So it is 1 in 15,000, here it is 2 and 67,890, after I do this assignment the object B will get the values of the data members of the object S but note that this object S will now be treated as an object of the base class, it is really an object of the savings class but because the savings class is derived from the base class so this object can also be treated as an object of the base class and in this assignment only the data members of the base class are going to be taken from the object S and assigned to the object B. If you think about it in terms of the operator equal to method invoked on the object B that will also do the same thing the default assignment operator for the base class will just copy the values of these data members id and balance from the right hand side of the assignment to the data members of the object on which this operator equal to method is called. We had studied this in a bit more detail in the last lecture. So here B dot id will have the value of S dot id which is 2 and B dot balance will have the value of S dot balance which is 67,890 and of course the value of S hasn't changed at all. So what you see is that when I do such an assignment when I assign an object of a derived class to an object of a base class then the additional data members in the derived class are sliced off or lost in this copy and this is to be expected if you also think about this assignment in terms of the operator equal to method of the base class. The operator equal to method the default assignment operator for the base class in this case can only copy values of the data members id and balance from the right hand side to the left hand side. Now here is the same base and derived class again and we just saw that it was okay to assign an object of the derived class to an object of the base class if you want to ask can we do it the other way round. So this is pretty much the same program but here I am trying to assign an object of the base class to the derived class. So once again just think about it logically an object of the base class cannot be thought of as an object of a derived class the base class has its own existence however an object of the derived class can be thought of as an object of the base class. So when I am doing this assignment I am taking an object of the base class and trying to assign it to an object of the derived class but an object of the base class is not an object of the derived class. So this assignment should be a problem if you think about it in terms of the operator equal to method when I do this assignment I am basically invoking the operator equal to method for the object S with the argument B. Now here the object S is of class savings, class savings does not have an explicitly defined assignment operator. So we are going to use the default assignment operator for the class savings what does the default assignment operator do it will try to copy the value of id, balance, age and ATM from the object on the right side of the assignment operator to the corresponding data members of the object S on the left side of the assignment operator. But the object on the right side of the assignment operator here is B and B does not have data members age and ATM. So the default assignment operator for the class savings expects to copy the data members id, balance, age and ATM of B into the corresponding data members of S. But B being an object of the class base does not have those data members. So once again this is a problem so whichever way you look at it there is a problem with this assignment and indeed there will be a compilation error. Now here we have just seen assignments of object of a derived class to an object of a base class what happens when we talk about assignments to pointers and references. So once again let us look at the base class let us look at the derived class and here is a main program in which I now have the stuff that we had before already. But instead of assigning an object of the derived class to an object of the base class or vice versa one of those is of course possible the other will give rise to a compilation error. Let us try to see what happens when we do assignments to pointers. So here is a pointer to an object of the base class here is a pointer to an object of the savings class and I am saying that I am going to assign the address of the object of the savings class to B pointer with whose type is a pointer to an object of the base class. Once again think about it logically an object of the derived class can be thought of as an object of the base class. So pointer to an object of the derived class can be thought of as a pointer to an object of the base class. So this assignment should be fine here like we had seen earlier an object of the derived class since it can also be viewed as an object of the base class can be directly assigned to an object of the base class. So here we are going to print out B dot id as the value of s dot id which is 2 and B dot balance is the value of s dot balance which is 67000. This we have already seen will lead to a compilation error because an object of the base class cannot be thought of as an object of the derived class. So it cannot be assigned to an object of the derived class. This as we just reasoned is fine because an object of the derived class can be thought of as an object of the base class and so address to an object of the derived class can be thought of as being of type pointed to the base class. So when I execute the statement I will be able to get the value of s dot id which is 4 here and the value of s dot balance which is 40000 here. However can I do this? Can I take the address of the base class and assign it to a pointed to the savings class once again if you think about it an object of the base class cannot be thought of as an object of this derived class. So therefore a pointed to the object of the base class is not of the type pointed to an object of the derived class. So this assignment is incorrect and it will lead to a compilation error. What about this statement? This is assigning an object of the derived class to a reference of the base class. But once again because an object of the derived class can also be thought of as an object of the base class this assignment should be fine and what will this assignment do? It will basically set bref dot id to s dot id and bref dot balance to s dot balance which in this case are 4 and 40000. So when I call this print function over here on the object bref, bref being a reference to the base class the print function of the base class is going to get called and not the print function of the derived class. So this distinction is important to note because the type of bref is reference to the base class. So bref dot print is going to call the print method of the base class and not of the derived class. So it is going to print base called printed by this print method. Now so far what we have seen is that it is not possible by default to take an object of a base class and assign it to an object of the derived class. Now suppose I really want to do this in my program and I want to define what this assignment means. What does it mean to assign an object of the base class to an object of the derived class? So C++ actually provides a mechanism to do this and we have encountered this in earlier lectures as well. This is called overloading operators. So for example in this case I have this base class which has a certain constructor and it has this assignment operator which expects the right hand side of the assignment operator to be an object of class A to be an object of the class base. Here is the derived class. The derived class of course does not inherit the assignment operator of the base class. We have seen this earlier. This is the constructor for the derived class and here I have explicitly defined an assignment operator for the derived class which can take an object of type base on the right hand side of the assignment operator. The default assignment operator of the derived class will expect an object of the same class on the right hand side but here I have overloaded the equal to operator and I have defined what to do when I have an object of the base class to the right hand side of the assignment operator and an object of the derived class on the left hand side. So here what am I saying? I am saying that if you see such an assignment where there is an object of the derived class on the left hand side and an object of the base class on the right hand side then you first invoke the assignment operator of the base class on the object on the right hand side. Recall that this is the scoping operator which allows us to invoke an operator in a base class even though it has been redefined in a derived class and so this is saying that simply invoke the assignment operator of the base class on the argument and whatever it does that should be the effect of this assignment operator with an object of base class on the right hand side and an object of the derived class on the left hand side. So now if I have a main program like this here I am instantiating an object of class b1 and this constructor gets invoked this initialization list initializes the value of id. I am instantiating two objects s1 and s2 of the class savings these arguments are used to initialize the data members base and age of these two objects and of course s2 is assigned s1 is fine both of them are objects of the same derived class. So the default assignment operator of the savings class is going to copy all data members of s1 to the corresponding data members of s2. So when I print s2.id and s2.age I will really get the corresponding values for s1 which is 11, 20. What happens here? Here I am taking an object of the savings class and assigning it to an object of the base class. So since an object of the savings class can also be viewed as an object of the base class. So this assignment operator of the base class is going to get invoked. So it will take the id of s1 and assign it to the id of b1 and it will also print this statement. It will print the statement base class operator and then when this statement is executed it will also print the id of b1 which is now the id of s1 and the id of s1 is 11. What happens here? b1.id is assigned 50. So this is of course directly assigning a data member of the object b1 to a constant. When I now do s2 is assigned b1 this is the interesting part. This is an object of the base class being assigned to an object of the derived class. By default this is not going to be allowed because an object of the base class cannot be treated like an object of the derived class. But note what we have done here. We have actually redefined the assignment operator in the derived class such that it can take an object of the base class on the right hand side. Remember when I do this assignment what is effectively being done is I am calling the operator equal to method of the object s2 with the argument b1 and this operator equal to method of the derived class s2 is of this derived class savings can accept an object of the base class on the right hand side that is how we have explicitly defined it. So now this statement should be fine it will not cause a compilation error because we have explicitly provided the definition of what such an assignment operator should be doing and what is this assignment therefore going to do it is simply going to call the assignment operator of the base class with the same argument and what happens when you call the assignment operator of the base class with the same argument. So b1.id will be copied to s2.id this statement is going to get printed base class operator this is going to actually get printed when this assignment happens and then when we execute this cout statement I will get the value of id for s2 as the value of id for b1 because of this assignment operator which was invoked from here and b1.id is 50 but the value of s2.age has not been changed this assignment operator does not change the value of age and so when it is called from here it only changes the value of id for s2 it does not change the value of the data member age for s2 so s2 will have the same value for the data member age as it had earlier which is 20. Now I have been saying that just like constructors and destructors assignment operators cannot be inherited normally by a derived class from a base class well c++ is a flexible enough language and if you really wanted to inherit this it actually provides a way to do this. Of course it will not happen by default it is not going to happen on its own you have to explicitly specify that I want to inherit an assignment operator of a base class like this inside a derived class like this. So this is what you say you say using base colon colon operator equals once again this is a scoping operator this is a keyword using this says that this derived class can use the assignment operator of the base class effectively inheriting the assignment operator of the base class. So unless you specify this explicitly the assignment operator is not going to be inherited unlike other methods which will be inherited unlike even other operators which will be inherited. So all operators other than the assignment operator will be inherited by default by derived class from a base class but the assignment operator is not going to be inherited by default. However you can explicitly specify that you want to inherit the assignment operator using this statement here. So now let us look at what will happen with this main program. So this is pretty much the same as we had seen earlier so here the default assignment operator of savings class will get invoked which means that all the data members of S1 will get copied to the data members of S2. So when you print this you will get S2.ID as 11 and S2.A as 20 when you do this assignment it is really the operator equal to of B1 which is of the base class will get invoked with the argument S1. S1 being an object of class savings can also be viewed as an object of class base and so this method is going to get executed you will see the statement being printed out and B1.ID will get the same value as S1.ID which is 11. So when you print out B1.ID you will see 11. This is the same assignment we saw earlier and now this is an assignment of an object of the base class to an object of the derived class normally this is not allowed but here because we have explicitly said that we want to inherit the assignment operator of the base class over here. So now when I invoke S2.operator equal to with the argument B1 I can use this assignment operator of the base class which accepts an argument of the base class and so basically when this assignment happens this method is executed S2.ID is set to B1.ID this message is printed out so you will see base class operator being printed out and after that if you try want to print out S2.ID you will basically get the value of B1.ID which is 50 but this method does not change S2.H so therefore S2.H will stay same as before we have already seen this earlier. Now let us talk about some special kinds of inheritance that often arise when you want to do real life programming. So the first such thing that we are going to look at is called multiple inheritance. Now think of the following situation I have a class automobile which has a particular data member mileage I have a class solar powered which has a particular data member called cell efficiency and I want to derive a class solar automobile from both these classes. I want to get the attributes of the class automobile and also the attributes of the class solar powered. How do we do this? In C++ this is done in pretty much the same way that we did derivation of one class from a single base class here we are doing derivation of one class from multiple base classes. So we say class solar automobile colon public this is the mode of inheritance or mode of derivation from the automobile class and then a comma public solar powered. So this is the mode of derivation from the solar powered class and then just like we did earlier I can define additional methods within this derived class and so on. Now suppose there is a data member called price in the class automobile and there is a data member called price also in the class solar powered and this class solar automobile is derived from both of these classes and similarly I could have a member function by a certain name in this class and a member function by the same name in this class and we want to ask how do we access these data members or member functions with the same name but in different base classes within this derived class. So well this is an example of that so here is the class automobile which has this data member price and also this member method get price this is of course the constructor just returns the price and here is the class solar powered which also has a data member called price and it also has a member method called get price which also returns the price and here is my class solar automobile which is derived from both automobile and solar powered in the public mode it has some additional data members number of seats and total price. How do I specify a constructor for this class solar automobile so here is a constructor for this class which takes a lot of arguments here 5 different arguments and this constructor is specifying that it should invoke the constructor for the class automobile with the arguments A and B it should invoke the constructor for the class solar powered with the arguments C and D so this constructor will be invoked this constructor will be invoked and it should also do an initialization so this is an initialization list so it should also initialize the data member number of seats with the value of the argument N and here is a member method of the class solar automobile here what I want to do is I want to get the price from the base class automobile I want to get the price from the base class solar powered and I want to add them up together but of course the same method name get price is being used in both so how do I unambiguously specify which of these member functions I want I am going to use the scoping operator here so I will say please invoke get price for the base class automobile please invoke get price for the base class solar powered add them up and then return that as the return value for this member function get total price of the derived class solar automobile so this example should tell you how to derive a particular class from multiple classes how to invoke the constructors of these multiple base classes and how to invoke methods by the same name unambiguously from these multiple base classes and now here is the main program where I have initialized some local variables and then here I call solar automobile here I instantiate an object of the class solar automobile with these parameters basically the constructor for the class solar automobile is going to be called with these parameters that in turn is going to call the constructor for automobile with certain values of parameters and the constructor for the class solar powered with certain values of parameters and finally when I say s.get total price the object s being of class solar automobile this function is going to get invoked so it will basically invoke the get price function of the base class automobile it will invoke the get price function of the base class solar powered add them up and then return so in this particular case it will add up 400,000 with 100,000 and return 500,000 now there is another kind of multiple inheritance which is also quite useful in practice and this is called diamond inheritance and we look at this now and you need to be a bit careful when you are using diamond inheritance otherwise there will be compilation errors. So suppose I have a class student which has a data member role number here is the constructor and here is a public method and let us say I have a class mid-sem which is derived from the class student has some additional data members here is the constructor which calls the constructor for student with a particular argument does some initialization of data members with values of some of the arguments and here is a public method get mid-sem marks of this class suppose we also have another class n-sem derived from the same class student which has its own additional data members its own constructor and its own public methods and suppose I want to derive a class total from both of these classes mid-sem and n-sem and here you can see why I was calling it diamond inheritance the pattern of inheritance really forms a diamond over here. But let us see what happens if I want to derive total from both mid-sem and n-sem we have seen how to specify multiple inheritance. So I will just try it class total colon public mid-sem public n-sem the mode of derivation from both of these base classes being public I can specify some additional data members and total marks this is the constructor for this class takes three arguments and it invokes the constructors for mid-sem and for n-sem which in turn will invoke the constructors for student and here is a member method which calls get mid-sem marks of the class mid-sem calls get n-sem marks of the class n-sem adds them up and returns of course note that I need not have used the scoping operator here because these two names are distinct in these two classes however I can use the scoping operator here also there is no problem with that. Now when we do this you know let us put the picture like this and in my main program if I am going to instantiate an object student one of class total. Now this objects student one of class total because it is derived from both mid-sem and n-sem will have an object of class mid-sem and an object of class n-sem within it and because mid-sem is derived from the class student and n-sem is derived from the class student that object of class mid-sem will have an object of class student within it and the object of class n sem will have another object of class student within it. So, really there are two objects of class student within an object of class total, this being the name of the object. So, here student 1 it will have two objects of class student within it. They will not necessarily be copies or identical, but there will be two objects of the class student and this can sometime be a problem. I mean because my inheritance is like a diamond. I may really want to say that I am really talking about the same student and the students mid sem marks and n sem marks. So, as you can see that intent is clear when I am specifying this two constructors of mid sem and n sem from the constructor of total. I want to specify the same roll number for the student in both of these constructors. So, I really want the same student object to be associated with both of these, but the way we have specified this class over here that is not going to happen I will get two copies of the student object. So, in this program what is going to happen is there will be two copies of the student object over here each copy will have roll 1001 and the mid sem copy of student will have mid sem marks is 32.2 the n sem copy will have the n sem marks initialized to 43.4 and now when I ask that can you invoke the method get roll number for the object student 1 and print it out note that there is a problem. The object student 1 really has two objects of the class student within it each object of class student has a get roll number. So, which of these methods get roll number am I talking about which object of class student there being two objects of class student within the object of class total. So, which of these two objects of class student should have its member method invoked when I am asking for student 1 get roll number. So, this call to the member function get roll number is ambiguous and you will get a compilation error. However, when I say student 1 dot get mid sem marks there is no ambiguity I am talking about this method of this base class for this derived class. Similarly, for student 1 dot get n sem marks there is no ambiguity. So, the question now is how do we prevent this in a C plus plus program how do we say that I do not need two copies of the student class I just need one copy of it I am trying to talk about the same student when I instantiate an object student 1 of the class total. So, in C plus plus there is a way to do this using what is called virtual derivation. So, here is our student class and here are the mid sem and n sem classes, but note that while specifying that mid sem is derived from the class student I have specified the keyword virtual here this is a virtual derivation and we will see exactly what this virtual derivation does particularly in the context of a diamond inheritance. So, here is the class total which is derived from both mid sem and n sem and this is pretty much the same as before except that in this diamond inheritance because mid sem is derived in the virtual mode from student and n sem is derived in the virtual mode from student. Therefore, when I instantiate an object of class total it would not be the case that the corresponding object of class mid sem will instantiate one object of class student and the corresponding object of class n sem will instantiate another object of class student. In fact, what is going to happen is that there will be exactly one object of the student class created for every total object. So, in this main program when I instantiate a variable student 1 of class total then unlike in the previous case this object student 1 will certainly have an object mid sem in it and will certainly have an object n sem in it, but this object mid sem and this object n sem will not have two separate copies of objects of the class student. In fact, they will only be one object of the class student. Now, once you understand this you will realize that because there is only one object of the class student who will call the constructor for this object will it come from the object of the class mid sem or will it come from the object of the class n sem. Well, in virtual derivation what happens is neither the class mid sem nor the class n sem is going to invoke the constructor for the class student although it is specified here because there is only one object of class student in an object of class total in this diamond inheritance pattern. So, essentially these calls to the constructors of the class student will be ignored in the definition of the class mid sem and the class n sem when I have this diamond inheritance otherwise of course this call will be made the constructor of student will be called if this class is not participating in a diamond inheritance, but when it is participating in diamond inheritance this constructor call will not be made similarly this constructor call will not be made. So, who is going to call the constructor of student and who is going to provide the parameter to that constructor that has to be done from the class total. So, that is why we have highlighted it here the constructor for the class total must now have an invocation of the constructor for the class student because neither the mid sem class nor the n sem class are going to invoke the constructor for the class student in this diamond inheritance when they have been derived virtually from the class student. So, now if this is my main program when I instantiate an object student one of the class total there is exactly one object of class student that is created this constructor is used to initialize the data members of that object this constructor is used to initialize the data members of the mid sem object in the object student one, but this call to the constructor of student is skipped and similarly for this call to the constructor of n sem. So, now if I print student from dot get roll number there is no ambiguity which get roll number I am calling because there is only one object of class student in the class total and so it is going to print as you can see the constructor passes the first argument. So, in this case roll which is 1 0 0 1 to the constructor of the class student and that is how the initialization of roll number happens. So, here I will see 1 0 0 1 being printed what about get mid sem marks. So, the constructor here has specified mid sem marks as 32.2. So, this constructor gets called with 1 0 0 1 and 32.2 this is skipped because this is diamond inheritance and this is virtual derivation. However, mid sem marks is set to 32.2. So, you see 32.2 being printed out here similarly for get n sem marks it is invoked here this constructor is invoked here with 1 0 0 1 and 43.4. However, this constructor is skipped once again because this is diamond inheritance and this is virtual derivation but n sem marks is set to 43.4. So, that is what you see here and then when I ask it to get the total it gets these two marks 32.2 and 43.4 adds them and prints out 75.6. So, in summary in this lecture we saw the relation between objects of base classes and derived classes and how to do assignments among them. We also saw how to do assignments to pointers and references of base classes and derived classes and we also saw two very interesting modes of inheritance called multiple inheritance and diamond inheritance and how these can be used in the right way. Thank you for your attention.