C++ 多态

多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。其实我看到过一句话:调用同名函数却会因上下文的不同而有不同的实现。我觉得这样更加贴切,还加入了多态三要素:(1)相同函数名  (2)依据上下文  (3)实现却不同;

多态是c++的特征之一

多态的分类:静态多态(静态联编)、动态多态(动态联编)
 
静态多态(静态联编):函数入口地址 是在 编译阶段 确定(运算符重载、函数重载)
 
动态多态(动态联编):函数入口地址 是在 运行阶段 确定(虚函数)
 1 class Animal
 2 {
 3 public:
 4     void sleep(void)
 5     {
 6         cout<<"animal 动物在睡觉"<<endl;
 7     }
 8 };
 9 
10 class Cat:public Animal
11 {
12 public:
13     void sleep(void)
14     {
15         cout<<"Cat 猫在睡觉!! 喵喵"<<endl;
16     }
17 };
18 void test01()
19 {
20     //用基类(指针或引用) 保存 子类对象(向上转换)
21     Animal *p = new Cat;
22     p->sleep();//调用的是基类的sleep
23 
24     Cat cat;
25     Animal &ob = cat;
26     ob.sleep();//调用的是基类的sleep
27 }

 总结:基类指针、引用 只能访问 子类对象中 基类部分 数据

3、使用基类指针、引用 访问 子类对象中的成员方法(虚函数)

使用virtual修饰成员函数 该成员函数就是虚函数。

1 class Animal
2 {
3 public:
4     //虚函数 
5     virtual void sleep(void)
6     {
7         cout<<"animal 动物在睡觉"<<endl;
8     }
9 };
vfptr虚函数指针 指向的是虚函数表(vftable)
vftable表存放的是 vfptr做保存的函数入口地址
注意://如果 Animal没有涉及到继承 函数指针变量 就指向自身sleep
 1 class Animal
 2 {
 3 public:
 4     //虚函数 本质 是一个函数指针变量
 5     virtual void sleep(void)
 6     {
 7         cout<<"animal 动物在睡觉"<<endl;
 8     }
 9 };
10 void test01()
11 {
12     //如果 Animal没有涉及到继承  函数指针变量 就指向自身sleep
13     Animal ob;
14     ob.sleep();
15 }

4、拥有虚函数的类 涉及得到继承 2-2

 1 class Animal
 2 {
 3 public:
 4     //虚函数 本质 是一个函数指针变量
 5     virtual void sleep(void)
 6     {
 7         cout<<"animal 动物在睡觉"<<endl;
 8     }
 9 };
10 class Cat:public Animal
11 {
12 public:
13     virtual void sleep(void)
14     {
15         cout<<"猫在睡觉!!喵喵"<<endl;
16     }
17 };

虚函数的定义要遵循以下重要规则: 

1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的。 

2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。 

3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。 

4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。 

5.构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。 

6.析构函数可以是虚函数,而且通常声名为虚函数。
 

同时需要了解多态的特性的virtual修饰,不单单对基类和派生类的普通成员 函数有必要,而且对于基类和派生类的析构函数同样重要

 

 

在面试中经常会出现这个问题:C++的动态捆绑机制是怎么样的?

 

首先,我们看看编译器如何处理虚函数。当编译器发现我们的类中有虚函数的时候,编译器会创建一张虚函数表,把虚函数的函数入口地址放到虚函数表中,并且在类中秘密增加一个指针,这个指针就是vpointer(缩写vptr),这个指针是指向对象的虚函数表。在多态调用的时候,根据vptr指针,找到虚函数表来实现动态绑定

 

posted @ 2020-03-25 22:34  进击的小尧好程序员  阅读(403)  评论(0编辑  收藏  举报