1. Static and dynamic and dynamic polymorphism
1. Static (compilation-time) polymorphic
function overloads belong to static polymorphism, such as compare function
bool compare(int,int){}
bool compare(double,double){}
compare (10,20); call compare_int_int determines the version of the called function
compare (10.5,20.5); call_compare_double_double
** Templates (function templates and class templates) ** are also polymorphic.
For example:
template
bool compare (T a, T b) {}
compare (10,20); => int instantiate a compare and
compare (10.5, 20.5); double instantiates a compare
2. Dynamic (runtime) polymorphic
concept:
In the inheritance structure, the base class pointer (reference) points to the derived class object, through which the pointer (reference) ** override method with the same name (virtual function) ** base class pointer Which derived class object will call the overriding method of which derived class object, called polymorphism.
For example:
pbase-> show (); the
bottom of the polymorphism is achieved through dynamic binding. The base class pointer points to who will access who's vfptr and then continue to visit who's vftable, and take it from the virtual function table. Of derived class objects
Below we implement an animal class to specifically describe the implementation process of dynamic polymorphism:
class Animal
{
public:
Animal(string name):_name(name){}
virtual void bark(){}
protected:
string _name;
};
//以下是动物实体类
class Cat :public Animal
{
public :
Cat(string name):Animal(name){}
void bark() { cout << _name << "bark:miao miao!" << endl; }
};
class Dog :public Animal
{
public:
Dog(string name) :Animal(name) {}
void bark() { cout << _name << "bark:wang wang!" << endl; }
};
class Pig :public Animal
{
public:
Pig(string name) :Animal(name) {}
void bark() { cout << _name << "bark:heng heng!" << endl; }
};
void bark(Cat &cat)
{
cat.bark();//引用变量访问虚函数,动态绑定
}
void bark(Dog& dog)
{
dog.bark();
}
void bark(Pig& pig)
{
pig.bark();
}
int main()
{
Cat cat("喵咪");
Dog dog("二哈");
Pig pig("佩奇");
bark(cat);
bark(dog);
bark(pig);
return 0;
}
The operation results are as follows:
Although it can run successfully, a set of bark API interfaces cannot achieve the "open-close" principle required by software design (closed for modification and open to extension). Changes to a derived class object require changes to its API interface.
So the following changes are made to this group of APIs:
void bark(Animal*p)
{
p->bark();
}
In the main function:
int main()
{
Cat cat("喵咪");
Dog dog("二哈");
Pig pig("佩奇");
bark(&cat);
bark(&dog);
bark(&pig);
return 0;
}
In this case, the Animal :: bark virtual function is implemented and dynamically bound.
p-> cat cat vftable & Cat :: bark access the virtual function table corresponding to cat, the bark method of cat is stored in the virtual function table, and so on ...
Second, the abstract class
In order to describe the whole concept more specifically, we first write an animal program as follows:
class Animal
{
public:
Animal(string name) :_name(name) {}
//纯虚函数
virtual void bark() = 0;
protected:
string _name;
};
//以下是动物实体类
class Cat :public Animal
{
public:
Cat(string name) :Animal(name) {}
void bark() { cout << _name << "bark:miao miao!" << endl; }
};
class Dog :public Animal
{
public:
Dog(string name) :Animal(name) {}
void bark() { cout << _name << "bark:wang wang!" << endl; }
};
class Pig :public Animal
{
public:
Pig(string name) :Animal(name) {}
void bark() { cout << _name << "bark:heng heng!" << endl; }
};
void bark(Animal* p)
{
p->bark();
}
int main()
{
Cat cat("喵咪");
Dog dog("二哈");
Pig pig("佩奇");
bark(cat);
bark(dog);
bark(pig);
return 0;
}
Our original intention of defining Animal is not to let Animal abstract the type of an entity. His use is:
1. string_name; let all animal entity classes directly reuse this attribute by integrating Animal
2. Keep a unified override / rewrite interface for all derived classes
In this regard, for the method of bark, in the base class, because it is not clear which animal, it is not possible to write the corresponding code specifically. At this time, we write bark like this virtual void bark () = 0; this is a pure virtual function .
Classes with pure virtual functions are called abstract classes;
note! ! ! Abstract classes cannot instantiate objects, but they can define pointers and reference variables
With the above understanding of the abstract class, let's write an abstraction of the car class to calculate the number of kilometers that the car can run
class Car
{
public:
Car(string name,double oil):_name(name),_oil(oil){}
//获取汽车剩余油量还能跑的公里数
double getLeftMiles()
{
//IL 10 * oil
return _oil * getMilesPerGallon();//发生动态绑定
}
string getName()const { return _name; }
protected:
string _name;
double _oil;
virtual double getMilesPerGallon() = 0;//存虚函数 因为对于不同的车他每公里所用的油量是不同的
};
class Bnze : public Car
{
public:
Bnze(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; }
};
//给外部提供一个统一的获取汽车剩余路程数的API
void showCarLeftMiles(Car& car)
{
cout << car.getName()<< "left miles:" << car.getLeftMiles() << "公里" << endl;
}
int main()
{
Bnze b1("奔驰",20.0);
Audi a("奥迪",20.0);
BMW b2("宝马",20.0);
showCarLeftMiles(b1);
showCarLeftMiles(a);
showCarLeftMiles(b2);
return 0;
}