Download presentation
Presentation is loading. Please wait.
1
Inheritance
2
Chapter Goals To understand the concepts of inheritance and polymorphism To learn how to inherit and override member functions To be able to implement constructors for derived classes To be able to design and use virtual functions
3
Inheritance Hierarchies
4
Inheritance Hierarchies
Shovels, rakes, and clippers all perform gardening tasks. They can be considered as specialized versions of the general ‘gardening tool’ type.
5
Inheritance Hierarchies
In object-oriented design, inheritance is a relationship between a more general class (called the base class) and a more specialized class (called the derived class). The derived class inherits data and behavior from the base class.
6
Inheritance IS-A
7
Inheritance: The IS-A Relationship
All cars are vehicles. (This is correct and good English.)
8
Inheritance: The IS-A Relationship
All cars IS-A vehicles. (Correct and … um … English?)
9
Inheritance: The IS-A Relationship
You may recall the UML notation HAS-A for containment. IS-A denotes inheritance.
10
Inheritance: The IS-A Relationship
All cars IS-A vehicles. (Correct… …when speaking object ively)
11
Inheritance: The IS-A Relationship
All Cars are Vehicles. All Motorcycles are Vehicles. All Sedans are Vehicles. C++ for Everyone by Cay Horstmann Copyright © 2012 by John Wiley & Sons. All rights reserved
12
Inheritance: The IS-A Relationship
Vehicles is the base class. Car is a derived class. Truck derives from Vehicle.
13
Inheritance: The IS-A Relationship
SUV derives from Car, which derives from Vehicle.
14
Inheritance: The IS-A Relationship
Truck IS-A Vehicle. SUV IS-A Car.
15
Inheritance: The IS-A Relationship
Everything about being a Vehicle is inherited by Cars and Trucks and SUVs.
16
Inheritance: The IS-A Relationship
Those things specific to Cars are only inherited by Sedans and SUVs.
17
Inheritance Hierarchies
I inherited my ROYALNESS from my parents who inherited it from their parents.
18
Inheritance Hierarchies
I’m a special version of my base class. I’m very special.
19
The Substitution Principle
Suppose we have an algorithm that manipulates a Vehicle object. Since a car IS-A vehicle, we can supply a Car object to such an algorithm, and it will work correctly. C++ for Everyone by Cay Horstmann Copyright © 2012 by John Wiley & Sons. All rights reserved
20
The Substitution Principle
The substitution principle states that you can always use a derived-class object when a base-class object is expected.
21
The Substitution Principle
Did you know you have already been working with class hierarchies? (No! Really?)
22
The Substitution Principle
Remember your friends cin and cout? (Yes.) Their types are in an inheritance chain. (Chains? Like prisoners?)
23
The Substitution Principle
No, silly. That’s just another phrase for inheritance hierarchy.
24
The Substitution Principle
Look: void process_input(istream& in); You can call this function with an ifstream object or with an istream object. Why?
25
The Substitution Principle
Because istream is more general than ifstream. void process_input(istream& in); This works by inheritance:
26
The C++ Stream Hierarchy
istream is the base class of ifstream. ifstream inherits from istream.
27
Quiz Time OK. QUIZ TIME!
28
Everyone likes taking quizzes.
Quiz Time OK. QUIZ TIME! Everyone likes taking quizzes. So let’s take one. (Oh no!)
29
You don’t like taking quizzes?
Quiz Time You don’t like taking quizzes? (Not really …) OK Let’s create a Quiz Question hierarchy. (Whew!)
30
Design Phase of Question Program
We will try to make this as general as we can because often quizzes consist of different kinds of questions: (We like multiple guess questions.) Fill-in-the-blank Choice (single or multiple) Numeric (we’ll allow approximate answers to be OK) Free response
31
Design Phase of Question Program
Here is the UML diagram that resulted from our analysis:
32
The Base Class: Question
At the root of this hierarchy is the Question type.
33
The Base Class: Question
We want a object of Question type to work like this: First, the programmer sets the question text and the correct answer in the Question object. C++ for Everyone by Cay Horstmann opyright © 2012 by John Wiley & Sons. All rights reserved
34
The Base Class: Question
Then, when it’s time to run the testing program with a user taking the test, the programmer asks the Question to display the text of the question: Who was the inventor of C++? The Question object displays this
35
The Base Class: Question
That programmer then gets the use’s response and passes it to the Question object for evaluation: Who was the inventor of C++? Your answer: Bjarne Stroustrup true The Question object displays this
36
The Base Class: Question – Member Variables
To work as shown, a Question object would contain: The question’s text string text; The correct answer string answer;
37
The Base Class: Question – Constructor
string text; string answer; What initial values should these have? What could possibly be a reasonable initial value? And – we’ll write mutators to allow setting them later. So a default Question constructor that does nothing is fine. The string class constructor gives us empty strings.
38
The Base Class: Question – Accessors
A Question object should be able to: Display its text void display() const; Check whether a given response is a correct answer bool check_answer(string response) const;
39
The Base Class: Question – Mutators
And have these mutators: Set the question’s text void set_text(string question_text); Set the correct answer void set_answer(string correct_response);
40
The Base Class: Question –
{ public: Question(); void set_text(string question_text); void set_answer(string correct_response); bool check_answer(string response) const; void display() const; private: string text; string answer; };
41
Question Class Test Program
Here’s a complete program to test our Question class. #include <iostream> #include <sstream> #include <string> using namespace std; class Question { public: /** Constructs a question with empty text and answer. */ Question();
42
Question Class Test Program
/** @param question_text the text of this question */ void set_text(string question_text); @param correct_response the answer to this question void set_answer(string correct_response); @param response the response to check @return true if the response was correct,false otherwise bool check_answer(string response) const;
43
Question Class Test Program
/** Displays this question. */ void display() const; private: string text; string answer; }; Question::Question() { }: void Question::set_text(string question_text) text = question_text; }
44
Question Class Test Program
void Question::set_answer(string correct_response) { answer = correct_response; } bool Question::check_answer(string response) const return response == answer; void Question::display() const cout << text << endl;
45
Question Class Test Program
int main() { string response; // Show Boolean values as true, false cout << boolalpha; Question q1; q1.set_text("Who was the inventor of C++?"); q1.set_answer("Bjarne Stroustrup"); q1.display(); cout << "Your answer: "; getline(cin, response); cout << q1.check_answer(response) << endl; return 0; }
46
boolalpha Did you notice this in the code?
// Show Boolean values as true, false cout << boolalpha; The boolalpha manipulator causes Boolean values to be displayed as the output strings: "true" for true and "false" for false – otherwise, numbers would be displayed.
47
Implementing Derived Classes
Now for those different kinds of questions. All of the different kinds IS-A Question so we code by starting with the base class (Question) and then we write code for what makes them special versions of more general Question type.
48
Implementing Derived Classes
I know about being special.
49
Implementing Derived Classes
Through inheritance, each of these types will have the data members and member functions set up in class Question. – plus “specialness-es” (We don’t rewrite the member functions) (code reuse in action – all right!)
50
Implementing Derived Classes
That’s me!
51
Implementing Derived Classes
We will start with the “choice question” kind of question: class ChoiceQuestion : public Question { public: // New and changed member // functions will go here private: // Additional data members // will go here };
52
Implementing Derived Classes
I’m his parent: the base class Implementing Derived Classes The : symbol denotes inheritance. I’m a derived class class ChoiceQuestion : public Question { public: // New and changed member // functions will go here private: // Additional data members // will go here };
53
Implementing Derived Classes
The keyword public makes sure this is an IS-A relationship. class ChoiceQuestion : public Question { public: // New and changed member // functions will go here private: // Additional data members // will go here }; ChoiceQuestion IS-A Question
54
Implementing Derived Classes
We are telling the compiler to start with the Question class and add these things to it. class ChoiceQuestion : public Question { public: // New and changed member // functions will go here private: // Additional data members // will go here };
55
Implementing Derived Classes – Analysis of the Problem
So what are these new things? How does a ChoiceQuestion differ from its base class? It’s use in the interaction with a user will be different:
56
Implementing Derived Classes – Analysis of the Problem
After a programmer has set the question text and the several multiple choice answers the ChoiceQuestion object is asked to display: In which country was the inventor of C++ born? 1: Australia 2: Denmark 3: Korea 4: United States The Question object displays all this
57
Implementing Derived Classes – Analysis of the Problem
The programmer then gets the user’s input, and sends it to the ChoiceQuestion object to see if it is correct. In which country was the inventor of C++ born? 1: Australia 2: Denmark 3: Korea 4: United States Your answer: 2 true The Question object displays this
58
Implementing Derived Classes – Coding
The code will have to make ChoiceQuestion be a specialized form of a Question object.
59
Implementing Derived Classes
ChoiceQuestion must have: Storage for the various choices for the answer Question has the text and correct answer, not these A member function for adding another choice A display function The designer of the Question class could not have known how to display this sort of multiple choice question. It only has the question itself, not the choices. In the ChoiceQuestion class you will have to rewrite the display function display. This is called overriding a member function.
60
Implementing Derived Classes – Coding
After specifying the class you are inheriting from, you only write the differences: class ChoiceQuestion : public Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
61
Implementing Derived Classes – Coding
Where is the set_text member function? Where is the string text; data member? Right there class ChoiceQuestion : public Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
62
ChoiceQuestion is one type,
Derived Classes class Question { public: Question(); void set_text(string question_text); void set_answer(string correct_response); bool check_answer(string response) const; void display() const; private: string text; string answer; }; ChoiceQuestion is one type, made of two subtypes. class ChoiceQuestion : public Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
63
It is based on the Question type so it has those parts.
Derived Classes members from class Question class Question { public: Question(); void set_text(string question_text); void set_answer(string correct_response); bool check_answer(string response) const; void display() const; private: string text; string answer; }; It is based on the Question type so it has those parts. class ChoiceQuestion : public Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
64
And, added to those parts from the Question type,
Derived Classes specializations class Question { public: Question(); void set_text(string question_text); void set_answer(string correct_response); bool check_answer(string response) const; void display() const; private: string text; string answer; }; And, added to those parts from the Question type, it has its own specializations (its specialness-es). class ChoiceQuestion : public Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
65
Derived Classes to make one type: ChoiceQuestion v class Question {
public: Question(); void set_text(string question_text); void set_answer(string correct_response); bool check_answer(string response) const; void display() const; private: string text; string answer; }; to make one type: ChoiceQuestion class ChoiceQuestion : public Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
66
Derived Classes – Syntax
67
Implementing Derived Classes – Coding
The derived class inherits all data members and all functions that it does not override.
68
Implementing Derived Classes – Coding
But… private means private.
69
Implementing Derived Classes – Coding
Consider: Choice_question choice_question; choice_question.set_answer("2"); (OK, a public method in a derived part.)
70
Implementing Derived Classes – Coding
How about: Choice_question choice_question; choice_question.answer = "2"; (Well, it did inherit that data member …)
71
Implementing Derived Classes – Coding
No, private means private! Choice_question choice_question; choice_question.answer = "2"; // will not compile - private (OK – private means private even if inherited.)
72
Implementing Derived Classes – Coding
This means that when you are writing the ChoiceQuestion member functions, you cannot directly access any private data members in Question. (Oh, dear. What to do?)
73
Implementing Derived Classes – Coding
A good design would be for this function to take a choice and somehow an indication that this choice is the correct answer. (bool! bool! bool!)
74
Implementing Derived Classes – Coding
Very good: ...but void ChoiceQuestion::add_choice(string choice, bool correct) { choices.push_back(choice); if (correct) // Convert choices.size() to string ostringstream stream; stream << choices.size(); string num_str = stream.str(); // Set num_str as the answer ... }
75
Implementing Derived Classes – Coding
Oh dear answer is private! void ChoiceQuestion::add_choice(string choice, bool correct) { choices.push_back(choice); if (correct) // Convert choices.size() to string ostringstream stream; stream << choices.size(); string num_str = stream.str(); // Set num_str as the answer ... }
76
Implementing Derived Classes – Coding
Happily, the designer of Question provided accessors! void ChoiceQuestion::add_choice(string choice, bool correct) { choices.push_back(choice); if (correct) // Convert choices.size() to string ostringstream stream; stream << choices.size(); string num_str = stream.str(); // Set num_str as the answer set_answer(num_str); } implicit parameter.set_answer(num_str);
77
Here is the class definition for ChoiceQuestion again.
Common Error Here is the class definition for ChoiceQuestion again. It’s wrong Can you find it? – we made a small mistake. class ChoiceQuestion : Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
78
Common Error: Private Inheritance
Aha! class ChoiceQuestion : Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
79
Common Error: Private Inheritance
If you do not specify public inheritance, you get private inheritance and everything is a mess. class ChoiceQuestion : private Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; };
80
Common Error: Private Inheritance
If you do not specify public inheritance, you get private inheritance and everything is a mess. (Be careful, son!)
81
Common Error: Replicating Base Class Members
You know all about private access: A derived class has no access to the private data members of the base class.
82
Common Error: Replicating Base Class Members
But when some programmers encounter a compiler error, They just start hacking. they (not you, of course) don’t stop and THINK. ChoiceQuestion::ChoiceQuestion(string quest_txt) { text = quest_txt; } COMPILER ERROR: accessing private data member text
83
Common Error: Replicating Base Class Members
And an “easy” fix seems to be to add the data member that the compiler is complaining about. ChoiceQuestion::ChoiceQuestion(string quest_txt) { text = quest_txt; } COMPILER ERROR: accessing private data member text
84
Common Error: Replicating Base Class Members
And an “easy” fix seems to be to add the data member that the compiler is complaining about. class ChoiceQuestion : public Question { ... private: vector<string> choices; string text; }
85
Common Error: Replicating Base Class Members
Oh dear! TWO test data members!
86
Common Error: Replicating Base Class Members
One set by the constructor and the other displayed! Oh dear! Oh Dear! OH DEAR!!!
87
Inheritance Is For Behaviors, Not Values
As you start working with inheritance, don’t overdo it! Consider a fleet of taxis, some are blue and some are those regular New York yellow cabs, but they all IS_A taxi.
88
Inheritance Is For Behaviors, Not Values
Consider doing this: class Taxi { ... }; class BlueTaxi : public Taxi { ... }; class NYCYellowTaxi : public Taxi { ... };
89
Inheritance Is For Behaviors, Not Values
What’s the only difference between a BlueTaxi and an NYCYellowTaxi? The color. That’s is not a behavior, it’s a value. Don’t create classes based on values. Make the value be a data member.
90
Inheritance Is For Behaviors, Not Values
The solution to the BlueTaxi, NYCYellowTaxi confusion: class Taxi { ... private: String color; };
91
Inheritance Is For Behaviors, Not Values
Create classes based on behaviors: like livery and metered cabs. class Cab { ... }; class MeteredCab : public Cab { ... }; class LiveryCab : public Cab { ... };
92
Calling the Base-Class Constructor
Consider constructing a derived-class. Like all constructors, they don’t construct: they initialize. But a derived-class constructor can’t initialize data members in the base-class. That’s the job of the base-class’ constructor. Oh dear.
93
Calling the Base-Class Constructor
If the base-class has a default constructor, we are in luck: that can be used. If not… We have to somehow “call” the base-class constructor from the derived-class’ constructor. Oh dear!
94
Calling the Base-Class Constructor
The initialization list to the rescue! We put the base-class’ constructor “call” in the initialization list. The initialization list code happens before the { } of the constructor so the base-class will be completely set up before any specializations take place.
95
Calling the Base-Class Constructor
Suppose, for the Question class, a constructor taking a String for the text had been written: then the ChoiceQuestion class constructor would have to take a String parameter to use to set Question’s text and call its constructor in the initialization list... …passing the data for it’s text data member. class Question { public: Question(String question_text); ... ChoiceQuestion::ChoiceQuestion(string question_text) : Question(question_text) }
96
Calling the Base-Class Constructor
97
Overriding Member Functions
Recall that our design requires that the display member function be rewritten in the ChoiceQuestion class. This is called overriding a member function.
98
Overriding Member Functions
ChoiceQuestion’s display method needs to: Display the question text. Display the answer choices.
99
Overriding Member Functions
The second part is easy – just a data member int ChoiceQuestion::display() const { // Display the question text ... // Display the answer choices for (int i = 0; i < choices.size(); i++) cout << i + 1 << ": " << choices[i] << endl; }
100
Overriding Member Functions
The first part seems easy too – call the display in Question: int ChoiceQuestion::display() const { // Display the question text display(); // Display the answer choices ...
101
Overriding Member Functions
Oh no! this points to me – and I have a display member function! int ChoiceQuestion::display() const { // Display the question text display(); // Display the answer choices ... implicit parameter.display();
102
Overriding Member Functions
I’m talking to myself!!! int ChoiceQuestion::display() const { // Display the question text display(); // Display the answer choices ... } implicit parameter.display();
103
Overriding Member Functions
The solution is to do what you said in the first place: Call Question’s display: int ChoiceQuestion::display() const { // Display the question text display(); // Display the answer choices ... }
104
Overriding Member Functions
The solution is to do what you said in the first place: Call Question’s display: int ChoiceQuestion::display() const { // Display the question text Question::display(); // Display the answer choices ... }
105
Overriding Member Functions
When you override a function, you usually want to extend the functionality of the base-class version. Therefore, you often need to invoke the base-class version before extending it.
106
Overriding Member Functions
Use the BaseClass::function notation.
107
Overriding Member Functions
However, you have no obligation to call the base-class function. Occasionally, a derived class overrides a base-class function and specifies an entirely different functionality.
108
A Program With ChoiceQuestion
In the following program, the definition of the Question class, which you have already seen, is placed into question.h, and the implementation is in question.cpp.
109
A Program With ChoiceQuestion
#include <iostream> #include <sstream> #include <vector> #include "question.h" class ChoiceQuestion : public Question { public: /** Constructs a choice question with no choices. */ ChoiceQuestion(); ch10/quiz2/test.cpp
110
A Program With ChoiceQuestion
/** Adds an answer choice to this question. @param choice the choice to add @param correct true if this is the correct choice, false otherwise */ void add_choice(string choice, bool correct); void display() const; private: vector<string> choices; }; ChoiceQuestion::ChoiceQuestion() { } ch10/quiz2/test.cpp
111
A Program With ChoiceQuestion
void ChoiceQuestion::add_choice(string choice, bool correct) { choices.push_back(choice); if (correct) // Convert choices.size() to string ostringstream stream; stream << choices.size(); string num_str = stream.str(); set_answer(num_str); } ch10/quiz2/test.cpp
112
A Program With ChoiceQuestion
void ChoiceQuestion::display() const { // Display the question text Question::display(); // Display the answer choices for (int i = 0; i < choices.size(); i++) cout << i + 1 << ": " << choices[i] << endl; } ch10/quiz2/test.cpp
113
A Program With ChoiceQuestion
int main() { string response; cout << boolalpha; // Ask a basic question Question q1; q1.set_text("Who was the inventor of C++?"); q1.set_answer("Bjarne Stroustrup"); q1.display(); cout << "Your answer: "; getline(cin, response); cout << q1.check_answer(response) << endl; ch10/quiz2/test.cpp
114
A Program With ChoiceQuestion
// Ask a choice question ChoiceQuestion q2; q2.set_text("In which country was the inventor of C++ born?"); q2.add_choice("Australia", false); q2.add_choice("Denmark", true); q2.add_choice("Korea", false); q2.add_choice("United States", false); q2.display(); cout << "Your answer: "; getline(cin, response); cout << q2.check_answer(response) << endl; return 0; } ch10/quiz2/test.cpp
115
Common Error: Forgetting the Base-Class Name
Don’t forget to use the BaseClass::memberFunction notation when you want to call a member function in your base class – especially when you are writing: DerivedClass::memberFunction (Yes, Mom.)
116
Common Error: Forgetting the Base-Class Name
Manager derives from Employee which has a method named get_salary. Careful: double Manager::get_salary() const { double base_salary = get_salary(); // Error—should be Employee::get_salary() return base_salary + bonus; }
117
The Slicing Problem Did someone say slice?
118
It would be nicer if all questions were collected in an array.
The Slicing Problem In the main function of that last program, there was some repetitive code to display each question and check the responses. It would be nicer if all questions were collected in an array. You could then loop to present them to the user:
119
because ChoiceQuestion is a special case of Question
The Slicing Problem const int QUIZZES = 2; Question quiz[QUIZZES]; quiz[0].set_text("Who was the inventor of C++?"); quiz[0].set_answer("Bjarne Stroustrup"); ChoiceQuestion cq; cq.set_text("In which country was the inventor of C++ born?"); cq.add_choice("Australia", false); ... quiz[1] = cq; for (int i = 0; i < QUIZZES; i++) { quiz[i].display(); cout << "Your answer: "; getline(cin, response); cout << quiz[i].check_answer(response) << endl; } This works because ChoiceQuestion is a special case of Question
120
However, is it really working? Here’s a run of the program:
The Slicing Problem However, is it really working? Here’s a run of the program: Who was the inventor of C++? Your answer: Bjarne Stroustrup true In which country was the inventor of C++ born? Your answer: Where are the choices?
121
When you assign a derived class to a base class memory location,
The Slicing Problem When you assign a derived class to a base class memory location, Slicing Happens! Ah! sharp knives…
122
The assignment copies text
The Slicing Problem The assignment copies text and answer just fine.
123
But where does choices go?
The Slicing Problem But where does choices go?
124
But where does choices go?
The Slicing Problem But where does choices go?
125
The Slicing Problem
126
The Slicing Problem
127
The Slicing Problem Sliced off…
128
The Slicing Problem
129
The Slicing Problem
130
The Slicing Problem SLICED OFF!
131
The Slicing Problem …and into the stewpot!
132
The assignment copies only the base portion.
The Slicing Problem The assignment copies only the base portion.
133
Pointers to Base and Derived Classes
To access objects from different classes in a class hierarchy, use pointers (to avoid slicing). I’m putting the knife away… …forever
134
Pointers to Base and Derived Classes
To access objects from different classes in a class hierarchy, use pointers (to avoid slicing). (pointers are sharp… hmm…)
135
Pointers to Base and Derived Classes
Pointers to the various objects all have the same size: the size of a memory address. (convenient)
136
Pointers to Base and Derived Classes
Pointers to base classes can hold pointers to ANY object publicly derived from it – as far down the inheritance chain as you want to go. (very general)
137
Pointers to Base and Derived Classes
The opposite will not work: Assigning a base pointer to a derived pointer location will generate a compiler error. (pointer well taken) (make that: point well taken)
138
Pointers to base and Derived Classes
To manage a set of ANY Questions including any IS-A Questions: Fill-in-the-blank Numeric Free response Choice (single)
139
Pointers to base and Derived Classes
To manage a set of ANY Questions and Questions inheriting from IS-A Questions Fill-in-the-blank Numeric Free response Choice (single) Choice (multiple – inherits from Choice (single)
140
Pointers to base and Derived Classes
… and Questions that are just a gleam in a programmer’s eye Fill-in-the-blank Numeric Free response Choice (single) Choice (multiple – inherits from Choice (single) Essay Essay written longhand in pomegranate juice
141
Pointers to base and Derived Classes
To manage all of these, use a vector<Question*> of an array of Question* and store only pointers to the different kinds of Questions Fill-in-the-blank Numeric Free response Choice (single) Choice (multiple – inherits from Choice (single) Essay Essay written longhand in pomegranate juice
142
Code for Pointers to base and Derived Classes
Notice the use of new and -> : Question* quiz[2]; quiz[0] = new Question; quiz[0] -> set_text("Who was the inventor of C++?"); quiz[0] -> set_answer("Bjarne Stroustrup"); ChoiceQuestion* cq_pointer = new ChoiceQuestion; cq_pointer -> set_text("In which country… …C++ born?"); cq_pointer -> add_choice("Australia", false); ... quiz[1] = cq_pointer;
143
Code for Pointers to base and Derived Classes
And the assignment of a derived-class pointer to a base: Question* quiz[2]; quiz[0] = new Question; quiz[0] -> set_text("Who was the inventor of C++?"); quiz[0] -> set_answer("Bjarne Stroustrup"); ChoiceQuestion* cq_pointer = new ChoiceQuestion; cq_pointer -> set_text("In which country… …C++ born?"); cq_pointer -> add_choice("Australia", false); ... quiz[1] = cq_pointer;
144
Vector of Pointers to Base to Manage Base and Derived
Question* quiz[2]; quiz[0] = new Question; quiz[1] = new ChoiceQuestion;
145
Using vector<Base*>
The code to present all questions – any kind of Question – is: for (int i = 0; i < QUIZZES; i++) { quiz[i] -> display(); cout << "Your answer: "; getline(cin, response); cout << quiz[i] -> check_answer(response) << endl; }
146
When you call the display member function on a
Virtual Functions (take a deep breath) When you call the display member function on a Question* pointer that currently contains a pointer to a ChoiceQuestion, you want the choices to be displayed, right? (Whew … yes.)
147
But that’s not what happens.
Virtual Functions But that’s not what happens. (Oh dear)
148
quiz[i]->display();
Virtual Functions For reasons of efficiency, by default, the call quiz[i]->display(); always calls Question::display because the type of quiz[i] is Question*. (Do we give up hope now and go home?)
149
that the function should be the one in the thing pointed to.
Virtual Functions In C++, you must alert the compiler that the function call needs to not be the default, that the function should be the one in the thing pointed to. (How?) You use the virtual reserved word for this purpose.
150
Notice where virtual is written.
Virtual Functions Notice where virtual is written. The virtual reserved word must be used in the base class. class Question { public: Question(); void set_text(string question_text); void set_answer(string correct_response); virtual bool check_answer(string response) const; virtual void display() const; private: ... };
151
All functions with the same name and parameter types
Virtual Functions All functions with the same name and parameter types in derived classes are then automatically virtual.
152
Virtual Functions Although not needed, it is considered good practice to write the virtual reserved word in the derived-class functions. class ChoiceQuestion : public Question { public: ChoiceQuestion(); void add_choice(string choice, bool correct); virtual void display() const; private: ... };
153
You do not write virtual in the function definition:
Virtual Functions You do not write virtual in the function definition: void Question::display() const { cout << text << endl; }
154
what you call is what you get!
Virtual Functions With virtual member functions, what you call is what you get! (Got it!) quiz[i]-> display();
155
The quiz vector collects a mixture of all kinds of Questions.
Polymorphism The quiz vector collects a mixture of all kinds of Questions. Such a collection is called polymorphic (literally, “of multiple shapes”).
156
Inheritance is used to express this commonality.
Polymorphism Objects in a polymorphic collection have some commonality but are not necessarily of the same type. Inheritance is used to express this commonality. virtual functions enable variations in behavior.
157
Virtual functions give programs a great deal of flexibility.
Polymorphism Virtual functions give programs a great deal of flexibility. The question presentation loop describes only the general mechanism: “Display the question, get a response, and check it”.
158
“Display the question”
Polymorphism Each object knows on its own how to carry out its specific version of these general tasks: “Display the question” (my way) and “Check a response” (my way).
159
Using virtual functions makes programs easily extensible.
Polymorphism Using virtual functions makes programs easily extensible.
160
Suppose we want to have a new
Polymorphism Suppose we want to have a new kind of question for calculations, where we are willing to accept an approximate answer. All we need to do is to define a new class NumericQuestion, with its own check_answer function.
161
and these new numeric questions.
Polymorphism Then we can populate any quiz vector with a mixture of plain questions, choice questions, and these new numeric questions. They will fit in just fine because: they IS-A Questions. (That’s so nice.)
162
The code that presents the questions need not be changed at all!
Polymorphism The code that presents the questions need not be changed at all! The calls to the virtual functions automatically select the correct member functions of the newly defined classes.
163
The Complete Program with Polymorphism
#ifndef QUESTION_H #define QUESTION_H #include <string> using namespace std; class Question { public: /** Constructs a question with empty question and answer. */ Question(); @param question_text the text of this question void set_text(string question_text); @param correct_response the answer for this question void set_answer(string correct_response);
164
The Complete Program with Polymorphism
/** @param response the response to check @return true if the response was correct, false otherwise */ virtual bool check_answer(string response) const; Displays this question. virtual void display() const; private: string text; string answer; }; #endif
165
The Complete Program with Polymorphism
#ifndef CHOICEQUESTION_H #define CHOICEQUESTION_H #include <vector> #include "question.h" class ChoiceQuestion : public Question { public: /** Constructs a choice question with no choices. */ ChoiceQuestion(); Adds an answer choice to this question. @param choice the choice to add @param correct true if this is the correct choice, false otherwise void add_choice(string choice, bool correct);
166
The Complete Program with Polymorphism
virtual void display() const; private: vector<string> choices; }; #endif
167
The Complete Program with Polymorphism
#include <iostream> #include "question.h" #include "choicequestion.h" int main() { string response; cout << boolalpha; // Make a quiz with two questions const int QUIZZES = 2; Question* quiz[QUIZZES]; quiz[0] = new Question; quiz[0]->set_text("Who was the inventor of C++?"); quiz[0]->set_answer("Bjarne Stroustrup");
168
The Complete Program with Polymorphism
ChoiceQuestion* cq_pointer = new ChoiceQuestion; cq_pointer->set_text("In which country… …C++ born?"); cq_pointer->add_choice("Australia", false); cq_pointer->add_choice("Denmark", true); cq_pointer->add_choice("Korea", false); cq_pointer->add_choice("United States", false); quiz[1] = cq_pointer; // Check answers for all questions for (int i = 0; i < QUIZZES; i++) { quiz[i]->display(); cout << "Your answer: "; getline(cin, response); cout << quiz[i]->check_answer(response) << endl; } return 0;
169
CHAPTER SUMMARY
170
CHAPTER SUMMARY
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.