Here we declared a virtual function bark(), but assign its address to 0. In this case, bark() is a pure virtual function. A class with pure virtual functions is called an abstract class. An abstract class can not be instantiated, but can have pointers and references:
int main() {
Animal a; // No
Animal *pa; // Yes
return 0;
}
Let's look at another example. Here we defined an abstract class Car, and has a method which returns remaining miles under the current fuel level.
Then we defined three cars of different brands, with different mileages per gallon.
class Benz : public Car {
public:
Benz(string name, double oil) : Car(name, oil) {}
double getMilesPerGallon() {return 20.0;}
};
​
class Audi : public Car {
public:
Audi(string name, double oil) : Car(name, oil) {}
double getMilesPerGallon() {return 18.0;}
};
​
class BMW : public Car {
public:
BMW(string name, double oil) : Car(name, oil) {}
double getMilesPerGallon() {return 19.0;}
};
Moreover, we provide an interface to get the remaining miles of the car, and passes in different objects:
double showCarLeftMiles(Car &car) {
cout << car.getName() << " " << car.getLeftMiles() << endl;
}
​
int main() {
Benz a("Benz", 20.0);
Audi b("Audi", 20.0);
BMW c("BWM", 20.0);
showCarLeftMiles(a); // Benz 400
showCarLeftMiles(b); // Audi 360
showCarLeftMiles(c); // BMW 380
return 0;
}
Now in showCarLeftMiles(), the parameter is a Car object instead of a pointer, isn't it a static binding? How can we achieve polymorphism? Of course it is a static binding here, but notice that in Car::getLeftMiles(), the virtual function getMilesPerGallon() is called with this->getMilesPerGallon(). Since *this is a Car pointer, it is still a dynamic binding, so the corresponding method of different objects is called.