虚函数以及纯虚函数

  多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。

  虚函数和纯虚函数都是实现多态的重要方法。本文就这两种方法进行分析以及比较

1、虚函数  

在基类中声明为 virtual 并在一个或者多个派生类被重新定义的成员函数

 语法规则:virtual 函数返回类型  函数名(参数表)  {函数体}

语法分析:虚函数的声明和定义和普通的成员函数一样,只是在返回值之前加入了关键字virtual。

       在基类当中定义了虚函数,可以再子类中定义和基类中相同函数名、相同参数、相同返回值和不同实现体的虚函数

       定义为虚函数是为了让基类函数的指针或者引用来指向子类。

#include<iostream>
using namespace std;

class A
{
public:
    void fun()
    {
        cout << "A::fun()..." << endl;
    }
};

class B :public A
{
public:
    void fun()
    {
        cout << "B::fun()...." << endl;
    }
};

int main()
{
    A *a = new A;              //A类指针指向A类对象
    a->fun();
    A *b = new B;              //A类指针指向B类 对象
    b->fun();

    delete a;
    delete b;
    return 0;
}

 分析代码:在上述代码中B为A的派生类,A *b=new B   是将基类的指针指向B 类对象。输出为:

显然程序没有实现我们想要的输出

#include<iostream>
using namespace std;

class A
{
public:
    virtual void fun()
    {
        cout << "A::fun()..." << endl;
    }
};

class B :public A
{
public:
    void fun()
    {
        cout << "B::fun()...." << endl;
    }
};

int main()
{
    A *a = new A;              //A类指针指向A类对象
    a->fun();
    A *b = new B;              //A类指针指向B类 对象
    b->fun();

    delete a;
    delete b;
    return 0;
}

 分析:可以看出利用虚函数可以实现多态,也就是说实现了通过不同对象的接口实现了不同的功能。

在使用虚函数是需要注意:

1、不能被声明为虚函数是函数类型有:构造函数,内联函数,静态成员函数

2、与构造函数不同,析构函数要尽量使用虚函数,当派生类的对象从内存中撤销的时候,会先调用派生类的析构函数然后再调用基类的析构函数,delete撤销对象时只调用了基类的析构函数,而没有执行派生类的析构函数。对此,我们将基类的析构函数声明为虚函数。

 3、在基类方法声明中使用关键字virtual,可以是相同函数名(返回值、函数名、参数表)在所有的派生类中是虚函数。

2、纯虚函数

在一些情况中,基类不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现由它的派生类去做。

 语法规则:virtual  返回值   函数名(参数表)=0;

 语法分析:纯虚函数可以让类先具有一个实现功能的名字,没有给出具体实现该功能的方法。凡是含有纯虚函数的类都叫抽象类

      这种类不能声明对象,只能作为基类去被继承,由子类去重写函数体,实现函数功能。

#include<iostream>
using namespace std;

class Shope
{
public:
    virtual double GetArea() = 0;           //定义为纯虚函数
    virtual double GetCir() = 0;            //定义为纯虚函数
};

class Circle :public Shope
{
public:
    Circle(float r):r(r){}                 
    double GetArea()                        //函数重写
    {
        return r * r*3.14;
    }
    double GetCir()                            //函数重写
    {
        return 3.14 * 2 * r;
    }
private:
    float r;
};

class Rectangle :public Shope
{
public:
    Rectangle(float a,float b):a(a),b(b){}
    double GetArea()                        //函数重写
    {
        return a * b;
    }
    double GetCir()                            //函数重写
    {
        return (a + b) * 2;
    }
private:
    float a;
    float b;
};

int main()
{
    Shope *ci = new Circle(4);           //基类指针指向Circle对象
    cout << "半径为4的圆周长为" << ci->GetCir() << ",面积为" << ci->GetArea() << endl;

    Shope *rec = new Rectangle(4.2, 5.3);//基类指针指向Rectangle对象
    cout << "长为4.2,宽为5.3的矩形,周长为" << rec->GetCir() << ",面积为" << rec->GetArea() << endl;
    return 0;
}

分析:在shope类中,声明的两个纯虚函数,GetArea(),GetCir();Circle类和Rectangle类去继承基类,重写纯虚函数。

   根据不同的形状,由不同的计算周长和面积的方法,具体实现方法需要派生类自己去重载。

使用纯虚函数的注意:

1、纯虚函数一定没有定义,它是用来规范派生类的行为,即接口。包含纯虚函数的抽象类,不能定义实例,但是可以声明指向该抽象类的具体类的指针或者引用

2、基类的纯虚函数在派生类中必须全部定义,否则派生类依然是抽象类,无法实例化。

3、总结

1、纯虚函数是特殊的虚函数,在纯虚函数中,同样可以让基类的指针指向子类对象。

2、纯虚函数:只提供一个接口,具体实现方法需要派生类自己去重载

   虚函数:提供接口,并提供默认的实现方法;派生类也可以根据需要自己去重载

   两者区别:纯虚函数在基类中不会提供实现方法,而虚函数需要提供。

猜你喜欢

转载自www.cnblogs.com/aaakihi/p/11743050.html