如何解释多态
静态(编译时期)的多态:
函数重载:在同一作用域底下,函数名字相同相同,但是函数的参数不同的一组函数称之为一组重载函数。
模板(函数模板,类模板):使用template<typename T>形式的格式化类型,这样写完之后,增加代码的复用性。
在编译阶段就决定了用那个函数
动态(运行时期)的多态:
在继承结构中,基类指针(引用)指向派生类对象,通过该指针(引用)调用同名覆盖方法(虚函数)
,基类指针指向哪个派生类对象,就会调用哪个派生类对象的同名覆盖方法,称为多态
多态底层是通过动态绑定来实现的,pbase-》访问谁的vfptr=》继续访问谁的vftable
=》当然调用的是对应的派生类对象的方法了
继承的好处
1.可以做代码的复用
2.在基类中给所有派生类提供统一的虚函数接口,让派生类进行重写,然后就可以使用多态了。
比如动物的基类
// 动物的基类
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; }
};
/*
下面的一组bark API接口无法做到我们软件涉及要求的“开-闭“原则
软件设计由六大原则 “开-闭“原则 对修改关闭,对扩展开放
*/
void bark(Animal *p)
{
p->bark(); // Animal::bark虚函数,动态绑定了
/*
p->cat Cat vftable &Cat::bark
p->dog Dog vftable &Dog::bark
p->pig Pig vftable &Pig::bark
*/
}
int main()
{
Cat cat("猫咪");
Dog dog("二哈");
Pig pig("佩奇");
bark(&cat);
bark(&dog);
bark(&pig);
return 0;
}
一般把什么类设置成抽象类?
解答:基类。
定义Animal的初衷,并不是让Animal抽象某个实体的类型
1.string _name; 让所有的动物实体类通过继承Animal直接复用该属性
2.给所有的派生类保留统一的覆盖/重写接口
拥有纯虚函数的类,叫做抽象类!(Animal)
Animal a; No!!!
抽象类不能再实例化对象了,但是可以定义指针和引用变量
修改过后的代码
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(); // Animal::bark虚函数,动态绑定了
}
// 汽车的基类
class Car // 抽象类
{
public:
Car(string name, double oil) :_name(name), _oil(oil) {}
// 获取汽车剩余油量还能跑的公里数
double getLeftMiles()
{
// 1L 10 * oil
return _oil * this->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;
// 静态绑定 call Car::getLeftMiles()
}
int main()
{
Bnze b1("奔驰", 20.0);
Audi a("奥迪", 20.0);
BMW b2("宝马", 20.0);
showCarLeftMiles(b1);
showCarLeftMiles(a);
showCarLeftMiles(b2);
return 0;
}