Cpp-虚函数

来源:互联网 发布:钢琴联系软件 编辑:程序博客网 时间:2024/06/05 14:38
虚函数,虚析构函数,纯虚函数,抽象类
虚函数
定义:在函数前加virtual,例子void virtual demo();
作用:多态的重要部分
一般来说父类中的函数被子类函数重写必须采用虚函数。
class Shape{public:    virtual double calcArea(){...}//虚函数    ....                                      //其他部分private:    ....};....class Circle:public Shape{public:    Circle(double r);    virtual double calcArea();//此处的virtual不是必须的,如果不加,系统会自动加                                        //上,如果加上则会在后续的时候看的比较明显(推荐加上)    ....private:    ....};....class Rect:public Shape{    Rect(double width,double height);    virtual double calcArea();private    ....};....
虚函数在使用中的限制(重要):
  • 普通函数不能是虚函数,也就是说这个函数必须是某一个类的成员函数,不可以是一个全局函数,否则会导致编译错误。
  • 静态成员函数不能是虚函数 static成员函数是和类同生共处的,他不属于任何对象,使用virtual也将导致错误。
  • 内联函数不能是虚函数 如果修饰内联函数 如果内联函数被virtual修饰,计算机会忽略inline使它变成存粹的虚函数。
  • 构造函数不能是虚函数,否则会出现编译错误
虚函数的实现:

       虚函数表指针:类中除了定义的函数成员,还有一个成员是虚函数表指针(占四个基本内存单元),这个指针指向一个虚函数表的起始位置,这个表会与类的定义同时出现,这个表存放着该类的虚函数指针,调用的时候可以找到该类的虚函数表指针,通过虚函数表指针找到虚函数表,通过虚函数表的偏移找到函数的入口地址,从而找到要使用的虚函数。

        当实例化一个该类的子类对象的时候,(如果)该类的子类并没有定义虚函数,但是却从父类中继承了虚函数,所以在实例化该类子类对象的时候也会产生一个虚函数表,这个虚函数表是子类的虚函数表,但是记录的子类的虚函数地址却是与父类的是一样的。所以通过子类对象的虚函数表指针找到自己的虚函数表,在自己的虚函数表找到的要执行的函数指针也是父类的相应函数入口的地址。

        如果我们在子类中定义了从父类继承来的虚函数,对于父类来说情况是不变的,对于子类来说它的虚函数表与之前的虚函数表是一样的,但是此时子类定义了自己的(从父类那继承来的)相应函数,所以它的虚函数表当中管于这个函数的指针就会覆盖掉原有的指向父类函数的指针的值,换句话说就是指向了自己定义的相应函数,这样如果用父类的指针,指向子类的对象,就会通过子类对象当中的虚函数表指针找到子类的虚函数表,从而通过子类的虚函数表找到子类的相应虚函数地址,而此时的地址已经是该函数自己定义的虚函数入口地址,而不是父类的相应虚函数入口地址,所以执行的将会是子类当中的虚函数。这就是多态的原理。

函数的覆盖和隐藏

父类和子类出现同名函数称为隐藏。

  • 父类对象.函数函数名(...);     //调用父类的函数
  • 子类对象.函数名(...);           //调用子类的函数  
  • 子类对象.父类名::函数名(...);//子类调用从父类继承来的函数。

父类和子类出现同名虚函数称为覆盖

  • 父类指针=new 子类名(...);父类指针->函数名(...);//调用子类的虚函数。
虚析构函数

[:->虚析构函数的特点:

  • 当我们在父类中通过virtual修饰析构函数之后,通过父类指针指向子类对象,通过delete接父类指针就可以释放掉子类对象

[:->理论前提:

  • 执行完子类的析构函数就会执行父类的析构函数

原理:

        如果父类当中定义了虚析构函数,那么父类的虚函数表当中就会有一个父类的虚析构函数的入口指针,指向的是父类的虚析构函数,子类虚函数表当中也会产生一个子类的虚析构函数的入口指针,指向的是子类的虚析构函数,这个时候使用父类的指针指向子类的对象,delete接父类指针,就会通过指向的子类的对象找到子类的虚函数表指针,从而找到虚函数表,再虚函数表中找到子类的虚析构函数,从而使得子类的析构函数得以执行,子类的析构函数执行之后系统会自动执行父类的虚析构函数。这个是虚析构函数的实现原理。

纯虚函数

class Shape{public:    virtual  double calcArea()//虚函数    {....}    virtual  double calcPerimeter()=0;//纯虚函数    ....};
纯虚函数只提供一个接口,基类不实现纯虚函数

抽象类

含有纯虚函数的类

接口类
1.没有任何数据成员
2.仅有成员函数
3.成员函数都是纯虚函数

注意:若父类有虚函数,则必须实现否则无法实例化,抽象类子类只有把抽象类当中的所有的纯虚函数都做了实现才可以实例化对象。







原创粉丝点击