多态的四种表现形式
在之前一提到多态,我下意识就是虚函数重写构成的运行时多态。直到看了一篇文章,才反应过来多态有四种表现形式。cpp-polymorphism
- 运行时多态(虚函数)
- 编译时多态(模板)
- 重载
- 类型转换
运行时多态(Subtype Polymorphism/Runtime Polymorphism)
运行时多态就是派生类重写基类的虚函数,在调用函数里,参数为基类的指针或引用,会构成多态。我之前写过一篇多态的原理,就是在讲多态(运行时多态)在底层是怎么实现的
举个例子:比如买票这个行为,成人去买就是全价,学生买就是半价票。但是不管成人还是学生都是人这个体系。所以我们需要根据谁来买票才能决定价格,这个时候就需要多态。
#include <iostream>
class ticket
{
public:
virtual void price() = 0;
};
class adult : public ticket
{
public:
virtual void price() override
{
std::cout << "成人全价!" << std::endl;
}
};
class student : public ticket
{
public:
virtual void price() override
{
std::cout << "学生半价!" << std::endl;
}
};
void BuyTicket(ticket& t)
{
t.price();
}
int main(void)
{
adult a;
student s;
BuyTicket(a);
BuyTicket(s);
return 0;
}
编译时多态(Parametric Polymorphism/Compile-Time Polymorphism)
编译时多态就是模板。在程序编译时,编译器根据参数的类型,就将生成某种类型的函数或类。我之前关于模板的总结:
举个简单的例子:Add() 函数是一个非常简单的函数,但是如果你写一个整型的 Add 函数,那么我想加 double 型的呢?你再写一个 double 型的 Add 函数,那么我想加 char 型的呢?
这个时候就用到了模板,我们先定义一个逻辑,具体类型等编译时再生成该类型的函数或类。
#include <iostream>
template<class T>
T Add(T lhs, T rhs)
{
return lhs + rhs;
}
int main(void)
{
Add(1, 2);
Add(2.0, 3.0);
Add('a', 'b');
return 0;
}
重载(Ad-hoc Polymorphism/Overloading)
函数名相同,参数不同就构成了重载。重载主要用于函数,当某个函数的功能无法处理某些参数的情况时,我们就可以重载一个函数来单独处理。
举个例子:比如说上面的 Add 函数,当前内置类型都可以处理,但是如果我传两个字符串怎么办?就不可以像刚才那么加了。得重载一个函数单独处理。
#include <iostream>
#include <string>
int Add(int lhs, int rhs)
{
return lhs + rhs;
}
std::string Add(const std::string& lhs, const std::string& rhs)
{
std::string ans(lhs);
ans += rhs;
return ans;
}
int main(void)
{
Add(1, 2);
Add("abc", "def");
return 0;
}
类型转换(Coercion Polymorphism/Casting)
类型转换主要分为四种:
- static_cast: 相当于隐式类型转换。
- const_cast: 这个可以去除一个 const 变量的 const 性质,使可以改变它的值。
- reinterpret_cast: 相当于强制类型转换。
- dynamic_cast: 这个可以使子类指针或引用赋值给父类指针或引用。
类型转换很简单,这里就不多赘述了。
Ending
这篇博客主要是强调了多态有四种形式,并不单单是运行时多态。