C++ Advanced Data Structures Chapter 8: Advanced C++ Topics Zhijiang Dong Dept. of Computer Science Middle Tennessee State University
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
Generalization and Specialization C++ In the real world, many objects are specialized versions of other more general objects. Insect is a very general type of creature with numerous characteristics. Since grasshoppers and bumble bees are insects, they have all the general characteristics of an insect. Additionally, they have special characteristics of their own. The grasshopper has its jumping ability, and the bumble bee has its stinger. Grasshoppers and bumble bees are specialized versions of an insect.
and the "Is-a" Relationship C++ When one object is a specialized version of another object, there is an "is-a" relationship between them. A grasshopper is an insect. A poodle is a dog. A car is a vehicle. A rectangle is a shape.
and the "Is-a" Relationship C++ When an is a relationship exists between classes, it means that the specialized class has all of the characteristics of the general class, plus additional characteristics that make it special. In object-oriented programming, inheritance is used to create is a relationship between classes. involves two classes: a base class (the general class), and a derived class (the specialized class). You can think of the base class as the parent, and the derived class as the child.
What a derived class inherits? C++ Every data member defined in the parent class (although such members may not always be accessible in the derived class) Every ordinary member function of the parent class (although such members may not always be accessible in the derived class!)
What a derived class doesn t inherit? C++ The base class s constructors and destructor The base class s assignment operator The base class s friends
What a derived class can add? C++ New data members New member functions New constructors and destructor New friends
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
in C++ C++ class Employee { public: Employee(); Employee(string name, string ssn); string getname() const; string getssn() const; double getnetpay() const; void setname( string name ); void setssn( string ssn ); void setnetpay(double netpay); void printcheck() const; private: string m_name; string m_ssn; double m_netpay; };
in C++ C++ class HourlyEmployee : public Employee { public: HourlyEmployee(); HourlyEmployee(string name, string ssn, double wagerate, double hours); double getrate() const; void setrate(double wagerate); double gethours() const; void sethours(double hoursworked); void printcheck(); //This function is overrided private: string m_wagerate; double m_hours; };
in C++ C++ class SalariedEmployee : public Employee { public: SalariedEmployee(); SalariedEmployee(string name, string ssn, double weeklysalary); double getsalary() const; void setsalary(double salary); void printcheck(); //This function is overrided private: string m_weeklysalary; };
public, protected, and private C++ public data and methods can be used by anyone private data and methods can be used only by methods and friends of the class protected data and methods can be used only by methods and friends of both the class and any derived class
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
C++ public inheritance public and protected members of the base class remain, respectively, public and protected members of the derived class. protected inheritance public and protected members of the base class are protected members of the derived class private inheritance public and protected members of the base class are private members of the derived class On all cases, private section of a base class cannot be accessed by a derived class
Other Class Relationship: has-a C++ Has-a relationship Also called containment A class has an object as a data member Cannot be implemented using inheritance Example: A has-a relationship between a pen and a ball class Pen {... private: Ball point; };
Other Class Relationship: As-a C++ Use private inheritance Example: Implement a stack as a list class Stack : private List Stack can manipulate the items on the stack by using List s methods The underlying list is hidden from the clients and descendants of the stack Private inheritance is useful when A class needs access to the protected members of another class, or If methods in a class need to be redefined
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
Override Member Function C++ A derived class inherits all the member functions of the base class If a derived class requires a different implementation for an inherited member function, the function can be redefined in the derived class, called overriding. When a member function is redefined, you must list its declaration in the definition of the derived class even though the declaration is the same as in the base class. If you don t wish to redefine a member function inherited from the base class, then it is not listed in the definition of the derived class.
C++ When you redefine a function definition, the new function definition given in the derived class has the same number and types of parameters. On the other hand, if the function in the derived class were to have a different number of parameters or a parameter of a different type from the function in the base class, then the derived class would have both functions. This is overloading.
What happens when a derived-class object is created and destroyed? C++ 1 Space is allocated (on the stack or the heap) for the full object (that is, enough space to store the data members inherited from the base class plus the data members defined in the derived class itself) 2 The base class s constructor is called to initialize the data members inherited from the base class 3 The derived class s constructor is then called to initialize the data members added in the derived class 4 The derived-class object is then usable 5 When the object is destroyed (goes out of scope or is deleted) the derived class s destructor is called on the object first 6 Then the base class s destructor is called on the object 7 Finally the allocated space for the full object is reclaimed
Upcast C++ 1 An upcast moves an object or a object pointer up a class hierarchy, from a derived class to a class it is derived from. 2 An upcast is an implicit conversion 3 Reason: is-a relationship. 4 Example: A hourly paid employee is an employee, and a salary paid employee is an employee.
Upcast: Code Example C++ // two function prototypes void print(employee); void print(employee*); int main( void ) { Employee John("John", "111-11-1111"); HourlyEmployee David("David", "222-22-2222", 13.0, 30); print(john); print(&john); } print(david); // because of upcast print(&david); // because of upcast John = David; // because of upcast return 0;
Upcast Pitfall Slicing Problem C++ Assigning a derived class object to a base class object slices off data. Any data members in the derived class object that are not also in the base class will be lost in the assignment. Any member function that are not defined in the base class are similarly unavailable to the resulting base class object. Example: HourlyEmployee David("David", "222-22-2222", 13.0, 30); Employee John; John = David; upcast John.getRate() ; // Compile Error: getrate sliced off
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
(Earlier Binding) C++ When a member function is called through an object or an object pointer, a decision needs to be made: which version of that function should be used parent s version or its own version If the decision is made at compile time, it is called static binding (earlier binding)
Similar to call member functions through an object pointer. : Examples C++ Example 1: HourlyEmployee John("John", "999-99-9999", 10.00, 40); John.getName(); // which function is called? Since getname is not redefined by HourlyEmployee, the version of its parent Employee is called. Example 2: John.printCheck(); // which function is called? Since printcheck is redefined by HourlyEmployee, and the function is called through a HourlyEmployee object, the version defined by class HourlyEmployee is called. Example 3: Employee David("David", "111-11-1111"); // which function is called? David.printCheck(); // which function is called? Since printcheck is called through a Employee object, the version defined by class Employee is called.
: Challenge C++ Sometimes, static binding is not what we want. Actually, it may cause disasters. Example: Employee *emp; HourlyEmployee John("John", "999-99-9999", 10.00, 40); emp = &John; //This is correct since John is an employee emp->printcheck(); // which version is called? Answer: The version defined in Employee class is called. Not the one defined in HourlyEmployee as we expect. Solution:
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
The decision of which member function version is called is made dynamically at run time C++ Dynamic binding use object s real type to select the appropriate method that is invoked at run time. To tell system to bind a member function call dynamically, define the member function as a virtual method Virtual member function is selected dynamically (at run-time) based on the type of the object, not the type of the pointer/reference to that object
Virtual Method C++ class Animal { public: virtual void eat() { cout << "I eat like a generic Animal. \n"; } }; class Wolf : public Animal { public: void eat() { cout << "I eat like a wolf!\n"; } }; class Fish : public Animal { public: void eat() { cout << "I eat like a fish!\n"; } }; class OtherAnimal : public Animal { };
Virtual Method C++ int main() { Animal *ananimal[4]; } ananimal[0] = new Animal(); ananimal[1] = new Wolf(); ananimal[2] = new Fish(); ananimal[3] = new OtherAnimal(); for(int i = 0; i < 4; i++) ananimal[i]->eat(); Output: I eat like a generic Animal. I eat like a wolf. I eat like a fish. I eat like a generic Animal.
Virtual Method A base class Animal could have a virtual function eat. C++ Subclass Fish would implement eat() differently than subclass Wolf. But you can invoke eat() on any class instance referred to as Animal, and get the eat() behavior of the specific subclass. This allows a programmer to process a list of objects of class Animal, telling each in turn to eat, with no knowledge of what kind of animal may be in the list. You also do not need to have knowledge of how each animal eats, or what the complete set of possible animal types might be.
Virtual Destructor C++ If a class has a virtual member function, then it is always a good idea to declare the destructor virtual. The compiler will perform static binding on the destructor if it is not declared virtual. This can lead to problems such as: When a base class pointer or reference variable refers a derived class object. If the derived class has its own destructor, it will not execute when the object is destroyed or goes out of scope. Only the base class destructor will execute. See example Animal.cpp
Virtual Method C++ Virtual methods must be class methods, i.e. they cannot be Ordinary stand-alone functions class data Static methods Virtual methods have a fixed interface, but derived implementations can change Supplying virtual keyword is optional when overriding a virtual method in derived classes. You can declare a virtual method in any derived class. Using virtual methods adds a small amount of time and space overhead to the class/object size and method invocation time. Polymorphic behavior is not possible when an object is passed by value.
Pure Virtual Method C++ class Shape { public: virtual double area(); }; class Rectangle : public Shape { public: double area(); }; class Triangle : public Shape { public: double area(); }; class OtherShape : public Shape { }; Question: How to implement the function area() in class Shape?
Pure Virtual Method C++ Define area() as a pure virtual method: class Shape { public: virtual double area() = 0 ; }; A pure virtual function is a virtual function that is required to be implemented by a derived class that is not abstract. Classes containing pure virtual methods are termed abstract. Abstract classes cannot be instantiated directly. A subclass of an abstract class can only be instantiated directly if all inherited pure virtual methods have been implemented by that class or a parent class.
Pure Virtual Destructors (NOT REQUIRED IN 3110) C++ The only effect of declaring a pure virtual destructor is to cause the class being defined to be an abstract class. Destructors are not inherited, therefore A pure virtual destructor in a base class will not force derived classes to be abstract classes Nor will any derived class be forced to declare a destructor Moreover, you have to implement the pure virtual destructor in the base class.
Chapter 8: Advanced C++ Topics C++ 1 C++ Syntax of 2
When to choose different bindings? C++ If you are sure that any derived classes will not want to override this operation dynamically (just redefine and hide) Use mostly for reuse or to form "concrete data types" When derived classes may be able to provide a different (more efficient, more functional) implementation that should be selected at run time. Used to build dynamic type hierarchies and to form abstract data types
Static v.s. C++ Efficiency v.s. flexibility are the primary tradeoffs between static and dynamic binding Static binding is generally more efficient since It has less time and space overhead It also enables method inlining Dynamic binding is more flexible since it enables developers to extend the behavior of a system transparently