summaryrefslogtreecommitdiff
path: root/03-11.md
blob: 042c6a16b4633034ccc84d29ba74ee8524017c3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
[\<- 03/09](03-09.md)

---

# Virtual Member Functions

## Example

```
class person{
	public:
		person(std::string name = "empty", int age = 0){
			this->name = name;
			this->age = age;
		}

		void print_name() const {
			std::cout << "Name is: " << get_name() << std::endl;
		}
	
	protected:
		std::string get_name() const { return name; };

	private:
		std::string name;
		int age;
};

class professor : public person{
	public:
		professor(std::string name = "empty", int age = 40, double salary = 0, bool nice = true) : person(name, age), salary(salary), nice(nice){};

		//Overriding the get_name function
		//Now this is a public function of this class
		std::string get_name() const{
			return (person::get_name() + ", he is nice!");
		}

	private:
		double salary;
		bool nice;
};

int main(int argc, const char* argv[]){
	professor myProf("Ben", 36);
	myProf.print_name();
	return 0;
}

---

//The output is:
Name is: Ben
```

## An example with a virtual

```
class person{
	public:
		person(std::string name = "empty", int age = 0){
			this->name = name;
			this->age = age;
		}

		void print_name() const {
			std::cout << "Name is: " << get_name() << std::endl;
		}
	
	protected:
		//This is a virtual now!!!
		virtual std::string get_name() const { return name; };

	private:
		std::string name;
		int age;
};

class professor : public person{
	public:
		professor(std::string name = "empty", int age = 40, double salary = 0, bool nice = true) : person(name, age), salary(salary), nice(nice){};

		//Overriding the get_name function
		//Now this is a public function of this class
		std::string get_name() const{
			return (person::get_name() + ", he is nice!");
		}

	private:
		double salary;
		bool nice;
};

int main(int argc, const char* argv[]){
	professor myProf("Ben", 36);
	myProf.print_name();
	return 0;
}
```

- If we use `virtual std::string get_name() const { return name; };`, then the output is:
	- `Name is: Ben, he is nice!`

- If we use `std::string get_name() const { return name; };`, then the output is:
	- `Name is: Ben`

## Example: game Class

- **Virtual member functions** are a new kind of member function that allows certain aspects of activating a function to be delayed until a program is actually running
- To make the explanation of virtual functions concrete, we'll present an example of a class called **game**, which will mke it easier for us to write programs that play various two-player games such as chess, checkers, or Othello

```
class game{
	public:
		//ENUM TYPE
		enum who { HUMAN, NEUTRAL, COMPUTER }; //Possible game outcomes

		//CONSTRUCTOR and DESTRUCTOR
		game() { move_number = 0; };
		virtual ~game() {};

		//PUBLIC MEMBER FUNCTIONS
		//The play function should not be overridden. It plays once game, with the human player moving first and the computer second
		//The computer uses an alpha-beta look ahead algorithm to select its moves. The return value is the winner of the game (or NEUTRAL for a tie)
		who play();

	protected:
		//OPTIONAL VIRTUAL FUNCTIONS (overriding these is optional)
		virtual void display_message(const std::string& message) const;
		virtual std::string get_user_move() const;
		virtual who last_mover() const { return (move_number % 2 == 1 ? HUMAN : COMPUTER); };
		virtual int moves_completed() const { return move_number; };
		virtual who next_mover() const { return (move_number % 2 == 0 ? HUMAN : COMPUTER); };
		virtual who opposite(who player) const { return (player == HUMAN ? COMPUTER : HUMAN); };
		virtual who winning() const;

		//VIRTUAL FUNCTIONS THAT MUST BE OVERRIDDEND (The overriding function function should call the original when it finishes)
		//Have the next player make a specified move:
		virtual void make_move(const std::string& move) { ++move_number; };
		//Restart the game from the beginning:
		virtual void restart() { move_number = 0; };

		//PURE VIRTUAL FUNCTIONS (these must be provided for each derived class
		//Return a pointer to a copy of myself:
		virtual game* clone() const = 0;
		//Computer all the moves that the next player can make:
		virtual void computer_moves(std::queue<std::string>& moves) const = 0;
		//A pure virtual function is indicated by "= 0" before the end of the semicolon in the prototype
		//The class does not provide any implementation of a pure virtual function

	private:
		//MEMBER VARIABLES
		int move_number; //Number of moves made so far
		//...
};
```

## Protected Members

```
protected:
	//OPTIONAL VIRTUAL FUNCTIONS (overriding these is optional)
	virtual void display_message (const std::string& message) const;
```

- The keyword **protected** indicates that the items that follow will be a new kind of member, somewhat between *public* and *private*
- A protected member can be used (and overridden) by a derived class - but apart from within a derived class, any protected member is private; It cannot be used elsewhere

## Virtual Member Functions

- The first protected member function in the game class is `display_message`

```
game::who game::play(){
	display_message("Welcome!");
	...
}
```

- When we play the game, the welcome message is printed at the start
- But, suppose that we write a game that needs to display messages by some other method
- Our derived class will inherit all the game class members, but it can override any method that it doesn't like

- Perhaps we want our Connect Four game to print "\*\*\*" before each displayed message (just to make the messages more exciting)
- We could override the `display_message` function so that `connect4::display_message` first prints "\*\*\*" and then prints the message
- With this approach, when the `play` method begins, it will activate `display_message("Welcome!")`, but what will this print?
	- If it uses `game::display_message`, then the word "Welcome!" appears by itself
	- If it uses `connect4::display_message`, then "\*\*\*Welcome!"

### When Onve Member Function Activates Another

- Normally, when a member function `f()` activates another member function `g()`, the version of `g()` that is actually activated comes from the same class as the function `f()`
- This behavior occurs even if the activated function `g` is later overridden, and `f` is activated by an object of the derived class
- In this example, this means that `game::play` normally would use `game::display_message`, even if a derived object activates the play method
- Solution: use "**virtual**"

### Activating a Virtual Member Function

- Whenever a **virtual** member function is activated, **the data type of the activating object is examined when the program is running**, and the correct version of the function is used
- For a virtual member function, the choice of which version of the function to use is never made until the program is running
- At run time, **the program examines the data type of the object** that activated the method, and thereby uses the correct version of the function

### Pure Virtual Functions and Abstract Classes

- A pure virtual function is indicated by "= 0" before the end of the semicolon in the prototype
- The class does not provide any implementation of a pure virtual function
- Because there is no implementation, any class with a pure virtual function is called an **abstract class** and **no instances of an abstract class may appear in a program**
- Abstract classes are used as base classes, and it is up to the derived class to provide an implementation for each pure virtual function

## Summary

- Object-oriented programming supports reusable components by permitting new derived classes to be declared, which automatically inherit all members of an existing base class
- All members of a base class are inherited by the derived class, but only the non-private members of the base class can be accessed by the programmer who implements the derived class
- The connection between a derived class and its base class can often be characterized by the "is-a" relationship
- An abstract base class (such as the game class) can provide a common framework that is needed by many derived classes
- An abstract base class has one or more pure virtual functions, which are functions that must be overridden before the class can be used