[\<- 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& 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