Unit - 04 Inheritance and Composition Reusing the code and functionality Unit Introduction This unit covers composition and inheritance Unit Objectives After covering this unit you will understand… Composition Inheritance Inheritance & constructor call sequence Multiple inheritance Upcasting & inheritance C++ casting operators Different types of Inheritance Inheritance vs. composition Composition (Aggregation) Creating and using objects of other class within a different class Also known as embedded object (or sub-object) Example: Composition class X { private: int m_Data; // data member public: X() {} // default constructor SetX (int k) // member function { m_Data = k; } }; class Y { private: int m_Data; Example: Composition (contd.) public: X x; // composition Y() {} //default constructor }; void main() { Y y; // creating object of class Y y.x.SetX(20); // Access/sets the embedded object } Inheritance Parent class is called the base class The class which inherits the base class is called the derived class; and has all the features of the base class, plus its own features Example: Inheritance class X { int m_Data; public: X() {} }; class Y : public X // class Y publicly inherits class X { int m_Data; public: Y() {} }; Constructor and Inheritance The constructor and destructor calls are automatic for the base class, in case the derived class object is created The order of base and derived class constructors and destructors are: base constructor derived constructor derived destructor base destructor Multiple Inheritance There could be two or more base class for a derived class It can cause ambiguity and is not recommended in normal cases There are ways to have single inheritance used instead of multiple inheritance to achieve the goal class Z : public X, public Y { // class definition } Example: Multiple Inheritance class A { public: void SomeFunction(void) { // function code } }; class B { public: void SomeFunction(void) { // function code } }; Example: Multiple Inheritance (contd.) class C : public A, public B { public: void MyFunction(void) { SomeFunction(); // Ambiguous as the compiler // does not know whether to //choose SomeFunction() of A or B } }; Upcasting and Downcasting Casting from derived to base class is known as Upcasting (implicit) Upcasting lose the derived class properties Casting from base to derived class is known as Downcasting Downcasting makes derived class’s properties available Example: Upcasting and Downcasting class Person { private: int Age; char* Name; char Gender; public: // accessor methods for member variables }; class Employee : public Person { private: char* Department; int EmployeeCode; public: // accessor methods for member variables }; Example: Upcasting and Downcasting (contd.) void main() { Person* pPerson = new Employee(); // upcast, implicit pPerson->GetName(); // fine pPerson->GetDepartment(); // error Employee* pEmployee = (Employee*)pPerson; // downcast pEmployee->GetDepartment(); // fine now } C++ Casting Operators Replace the traditional, parenthetic casting technique Explicit Self documenting Signal a type conversion Less risk of illegal cast and data corruption C++ Casting Operators (contd.) static_cast Compile-time cast Casting classes that provide static polymorphism (non-virtual classes) dynamic_cast const_cast Run-time cast, to cast classes that provide dynamic polymorphism (virtual classes) To remove const-ness reinterpret_cast For conversion of unrelated types Example: static_cast // Note that Base is not a virtual class class Base{ }; class Derived : public Base { }; void f(Base* pBase) { Derived* pDerived = static_cast<Derived*>pBase } // Also, enum fruit{apple=0, orange=1, banana=2}; int x = 2; fruit f1 = static_cast<fuit>(x); // converts an int to enum Example: dynamic_cast // Note that Base is a virtual class class Base{ virtual void f(); }; class Derived : public Base { void f (){} }; void f(Base* pBase) { //Derived* pDerived = static_cast<Derived*>pBase // error // use dynamic_cast instead Derived* pDerived = dynamic_cast<Derived*>pBase // fine } Example: const_cast double f(double& d); // f accepts reference to type double void g(const double& d) { // while calling f() the const-ness of d is removed double val = f( const_cast<double&>(d) ); } Example: reinterpret_cast // a practical example could returns hash code based on an // address unsigned short Hash(void* p) { // reinterpret casting a pointer to integral value unsigned int val = reinterpret_cast<unsigned int> (p); val = val & 16; // hash code formula return (unsigned short)val; // cast to the returned type } void main() { int a[10]; for (int i = 0; i < 10; i++) { cout << Hash(a + i) << endl; // using Hash() } } Inheritance Types Inheritance has three types: public private protected The following chart gives the accessibility details of the inheritance types: Private Variable Protected Variable Public Variable Private Function Protected Function Public Function Public Inheritance Protected Inheritance Inaccessible Inaccessible Protected Protected Public Protected Inaccessible Inaccessible Protected Protected Public Protected Private Inheritance Inaccessible Private Private Inaccessible Private Private Inheritance Types (contd.) Protected Function in the base class is treated as Private Function in the child class (taking the example of the value in bold), when inherited using the private keyword class X : public Y, private Z, protected W { // class definition } Inheritance vs. Composition Composition is generally used when you want the features of an existing class inside your new class, but not its interface Use inheritance for sub-typing, where you want your new type to have exactly the same interface as the existing type (plus any other member functions you want to add) Unit Summary In this unit you have covered … Composition Inheritance Multiple inheritance Upcasting & inheritance C++ casting operators Types of inheritance Inheritance vs. composition