一篇文章带你认识多态并学会多态的使用
ps:本篇文章暂时不讲多态的底层实现细节,只是单纯认识多态和学习多态使用方法.因为多态的底层较为复杂,全写进一篇文章可能造成篇幅过长,下次想起来的话下次会补写.
什么是多态?
从生活客观事实角度管中窥豹
计算机语言是描述世界的语言,因此多态的概念在生活中也是普遍存在的.多态就是相同的行为,不同的对象触发会产生不同的结果.比如去医院挂号,我去的话需要老老实实排队,但是军人会有专属优先窗口.再比如我们买票,成人票的话就是全款,但是我可以买学生票就会便宜很多.上面的两个例子中,挂号这个行为我和军人就是不同的对象,去调用时出现了不同的结果,同样的买票的行为,成人和学生不同的对象去调用也产生了不同的结果.类似的还有各种平台的权限控制等等这里就不在例举了.
那在计算机语言(C++)中多态是怎样的呢?
上面的例子中对多态的描述都是存在行为和对象是一对多的映射关系.那我们用计算机语言描述时也应该是这样.我们以买票为例.我下面先写接口逻辑不写实现.
class Person{};
class Student{};
int main()
{
Person p;
Student s;
BuyTicket(p);
BuyTicket(s);
return 0;
}
这里的接口就是BuyTicket();
对象就是Person
和Student
.我们就是希望运行Buyticket(p);
和Buyticket(s)
时产生不同的结果,这里可能会有同学问了:这里不是本来运行结果就不同吗?因为这里函数的参数不一样啊,结果当然不一样.
,其实这样的理解还是没抓住重点.多态描述的结果不同并非是因为参数的不同产生的,而是因为这里的类型不同产生的.这里再举一个例子,假如我是一个老师,我在学校有自己的办公室,在我还是这个老师身份的时候,我当然可以自由出入我的办公室,但是很不幸我昨天被学校开除了,那我今天还能进这个办公室吗?答案自然是否定的,这里的不同结果并非是因为参数差异产生的,从始至终都是我一个人,变的只有我的身份,这里的身份,就是多态的关键.
经过这样的解释之后应该可以明白我上面的代码表达的意思了吧?现在我们终于认识了多态,下面就开始学习使用.
怎么实现多态呢
认识虚函数(不讲原理,篇幅很短)
在这里我们只需要认识一个关键字virtual
,顾名思义就是虚无,加上这个关键字的函数就是虚函数.代码示例:
class B
{
public:
virtual void print(){cout<<B()<<endl;}
};
好了,你已经认识虚函数了,接下来让我们打开多态的大门吧.
构成多态的条件(一看就会)
- 虚函数的重写.
虚函数的重写嘛,其实就和我们之前讲继承时提到的隐藏差不多,只是这里多了虚的属性,并且要求不只是名字相同,参数和返回值也必须相同.(其实也有例外了,这里说明一下,协变和析构函数重写并不一定是这三者都相同,篇幅原因,下次讲原理时候再展开说)下面代码示例:
class B
{
public:
virtual void print(){cout<<B()<<endl;}
};
class D : public B
{
public:
virtual void print(){cout<<D()<<endl;}
};
很简单,就只是加了个
virtual
关键字而已.
- 必须是基类的指针或引用来调用.
没什么好解释的直接上代码吧:
class B
{
public:
virtual void print(){cout<<B()<<endl;}
};
class D : public B
{
public:
virtual void print(){cout<<D()<<endl;}
};
void func(B& b){b.print();}
int main()
{
B b;
D d;
func(b);
func(d);
return 0;
}
这里就是通过
func(B& b)
函数的参数来实现基类的引用调用,一看就会.
同时满足这两个条件就构成多态了,上面的代码执行结果自然就是func(b)打印B(),func(d)打印D().
本期多态使用部分就到这里了,这里我提一个问题:
假如我并没有选择多态,仅仅是通过派生类把从基类继承来的成员函数通过重定义隐藏掉,再去调用不是也能实现不同对象不同结果的效果吗? 这与多态有什么区别? 这样写存在什么问题?
因为背后牵扯到的逻辑太多了,问题的答案我先按下不表,但通过这个问题我想告诉大家,其实多态难点并不在使用,如果只是知道怎么用离真正理解多态差太多太多了,下一期我会对多态庖丁解牛,让你真正看清多态的本质.点个关注不迷路.