一、动态多态
我们知道,通过基类定义虚函数,派生类重写基类的虚函数,在基类绑定派生类时,调用同名虚函数时,可以发生多态,这样的多态称为动态多态。
这样的多态需要在运行时才能确定调用的成员函数是哪一个,这里不过多介绍。
下面是动态多态的一个范例:
//动态多态
class Human {
public:
Human() {
std::cout << "调用了Human的构造函数\n";
}
virtual void eat() {
std::cout << "人类以米饭和面食为主!\n";
}
virtual ~Human() {};
};
class Men :public Human {
public:
virtual void eat() {
std::cout << "男人喜欢吃面食!\n";
}
};
class Women :public Human {
public:
virtual void eat() {
std::cout << "女人喜欢吃米饭!\n";
}
};
void Test1() {
Men objmen;
Women objwomen;
//基类绑定派生类
Human&obj1 = objmen;
Human& obj2 = objwomen;
//运行时发生多态(动态多态)
obj1.eat();
obj2.eat();
}
我们用父类引用绑定子类对象(也可以用父类指针),这样我们在调用子类虚函数时就能发生多态。
运行结果如下:
二、静态多态
动态多态只有在运行时才能确定,并且需要继承和虚函数,会产生额外的虚函数表和虚函数指针,降低一定的执行效率。
这里,我们可以使用模板来实现多态的效果,去掉繁琐的继承和虚函数
class Men2 {
public:
void eat() {
std::cout << "男人喜欢吃面食!\n";
}
};
class Women2 {
public:
void eat() {
std::cout << "女人喜欢吃米饭!\n";
}
};
//多态在模板上的应用(静态多态)
template<typename T>
void eatTmpl(T& obj) {
obj.eat();
}
void Test2() {
Men2 objmen;
Women2 objwomen;
//编译期间就确定调用的函数(静态多态)
eatTmpl(objmen);
eatTmpl(objwomen);
}
这里我们使用了一个函数模板,当传入不同的类型的对象时,就会自动推导出
T
T
T类型。
我们知道,函数模板的实例化是在编译期间就确定的(存在对函数模板的调用),所以这样的多态可以称为静态多态。
运行结果如下, 同样实现了多态的效果