c++笔记--多态

C++的多态必须满足两个条件

1 必须通过基类的指针或者引用调用虚函数

2 被调用的函数是虚函数,且必须完成对基类虚函数的重写

虚函数:只能是类中非静态成员函数(virtual)(构造函数不可,析构函数可以定义为虚函数)

 虚函数重写(覆盖):子类与父类中的虚函数有相同的名字,返回值,参数列表

子类重写虚函数可以不加virtual

析构函数的重写:只要父类的析构函数用virtual修饰,无论子类是否有virtual,都构成析构 

用final修饰的函数无法重写,用override修饰的需要重写

协变(虚函数重写的例外)

子类的虚函数与父类的虚函数返回值可以不同,也能构成重载。但子类的返回值是子类的指针或引用,父类的返回值是父类的指针或引用,且返回值代表的两个类也成继承关系

class Person
{
  public:
   virtual Person* fun()//返回父类指针
   {
      cout << "Person->fun()" << endl;
      return nullptr;
   }
};
class Student
{
   public:
            //返回子类指针,虽然返回值不同,也构成重写
   virtual Student* fun()//子类重写父类虚函数
   {
     cout << "Student->fun()" << endl;
     return nullptr;
   }
};

重载、重写(覆盖)、重定义(隐藏)

1、重载:重载函数处在同一作用域,函数名相同,函数列表必须不同

2、重写:必须是虚函数,且在父类和子类中,返回值,参数列表,函数名必须完全相同(协变除外)

3、重定义:子类和父类的成员变量相同或函数名相同,子类隐藏父类的对应成员

抽象类

在虚函数后面加上=0就是纯虚函数,有虚函数的类就是抽象类(接口类)。抽象类无法实例化出对象。抽象类的子类也无法实例化出对象,除非重写父类的虚函数

class Car
{
public:
    virtual void fun() = 0; //不用实现,只写接口就行。
}

作用:

强制子类重写虚函数,完成多态

表示某些抽象类


实现继承:普通函数的继承

接口继承:虚函数的继承

虚函数重写后只会继承接口,重写实现,如果不用多态,别把函数写成虚函数

class A
{
   public:
   virtual void fun(int val = 0)//父类虚函数
   {
     cout <<"A->val = "<< val << endl;
   }
   void Fun()
   {
      a->fun();//传过来一个子类指针调用fun()
   }
};
class B: public A
{
   public:
    virtual void fun(int val = 1)//子类虚函数
    {
       cout << "B->val = " << val << endl;
    }
};


B b;
A* a = &b;
a->Fun();
//结果是什么呢?
//B->val = 0
//子类对象切片给父类指针,传给Fun函数,满足多态,会去调用子类的fun函数,但是子类的虚函数继承了父类的接口,所以val是父类的0.

虚函数表

子类跟父类一样有一个虚表指针。

子类的虚函数表一部分继承自父类。如果重写了虚函数,那么子类的虚函数会在虚表上覆盖父类的虚函数。

本质上虚函数表是一个虚函数指针数组,最后一个元素是nullptr,代表虚表的结束。

所以,如果继承了虚函数,那么

1 子类先拷贝一份父类虚表,然后用一个虚表指针指向这个虚表。

2 如果有虚函数重写,那么在子类的虚表上用子类的虚函数覆盖。

3 子类新增的虚函数按其在子类中的声明次序增加到子类虚表的最后

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值