CS 541 Lecture -*- Outline -*- * Inheritance (Derived Classes) mechanism for incremental programming allows one to extend function of class without changing code ** terminology Subclass called a derived class Superclasses called base classes (multiple inheritance) ** simple example, inheritance for structs recall that a class is just a struct with default private. (a struct is just a class with all public members) --------- // INHERITANCE struct employee { char * name; short age; short department; int salary; employee* next; }; struct manager : public employee { employee* group; }; --------- *** subtyping pointers to public base class can point to objects of derived class doesn't apply if base class is private! same applies to references interpreted as coercion from derived* to base* opposite conversion from base* to derived* not done ---------- // SUBTYPE POLYMORPHISM int main() { manager m; employee e; employee* elist; elist = &m; m.next = e; e.next = 0; } ---------- *** scope scope of public members of base class extends to derived class and implementations of its member funs => names of base class public members can be used without qualification in derived class scope of private members is just that class --------- // ACCESS CONTROL class employee { private: char * name; short age; short department; int salary; public: employee* next; void print(); }; class manager : public employee { private: employee* group; public: void print(); }; void manager::print() { employee::print(); // not just print()! // ... print manager info } --------- *** scope of protected members a member may be declared to have access protected means private to clients, but visible to subclasses as protected members ** kinds of derivation (inheritance) can explicitly declare each base whether it is public or private (if don't say, it's private for classes, but public for structs) (no such thing as protected base class) *** public base classes every public member of base class is public member of derived similarly for protected private members of base class are still represented e.g., next is a public member of manager (derived structs always have base class public) *** private base classes private base class allows one to restrict the interface imprortant if no semantic subtyping every public member of base class is private member of derived as are protected and private e.g., if employee were private base of manager, then next would be a private member of manager. can make public individual public members of private base similarly for protected ------------ // PRIVATE DERIVATION class smanager : private employee { employee* group; public: employee::next; // makes next public void print(); }; ------------ employee is private base class, public members of smanager are next, print. similarly, can make protected, protected members of private base ** constructors if the base class has a constructor, must be called, preferably like a named member ------------------ // CONSTRUCTORS AND INHERITANCE class base { // ... public: base(char* n, short t); ~base(); }; class derived : public base { base m; public: derived(char* n); ~derived(); }; derived::derived(char* n) : base(n,10), m("member", 123) { // ... } ------------------ constructors called in this order: base, then members, finally the body of derived class destructors in opposite order the derived class's body, then the members, then the base ** Virtual operations give dynamic binding must have definition even in base class but can define to be 0, which means not implemented e.g., virtual void rotate(int) = 0; ---------------- // VIRTUAL OPERATIONS class employee { char * name; short age; short department; int salary; public: employee* next; virtual void print(); }; class manager : public employee { employee* group; public: // virtual, because declared so in base void print(); }; void manager::print() { employee::print(); // statically bound // ... print manager info } --------------- --------------- // USE OF SUBTYPE POLYMORPHISM void print_list(employee* ll) { for (; ll; ll=ll->next) ll->print(); //dynamic binding } main() { employee e; e.name = "J.B"; e.department = 1234; e.next = 0; manager m; m.name = "J.S."; m.department = 1234; m.next = &e; print_list(&m); } -------------- ** Multiple inheritance name conflicts in function members must be resolved at each use In diamond shaped inheritance graph, get two copies of inhertied components ------------ // MULTIPLE INHERITANCE class A : public L { /* ... */ }; class B : public L { /* ... */ }; class C : public A, public B { /* ... */ }; ------------ in the above, an object of type C has two components of type L, named A::L and B::L. *** Virtual base class use to get only one copy of a base class (requests sharing) ------------ // WITH VIRTUAL BASE CLASSES class A : public virtual W { /* ... */ }; class B : public virtual W { /* ... */ }; class C : public A, public B, public virtual W { /* ... */ }; ------------ only one copy of W in a C object. all redefinitions of a virtual function of a virtual base class must occur on a single path through the DAG only slightly more expensive than single inheritance virtual fun call 5-6 mem refs vs. 3-4 ** motto: don't edit, inherit and customize