Fork me on GitHub

至简

Be simple

为了寻找你,我把自己搬进鸟的眼睛,经常盯着路过的风。


虚函数及实例


简介

虚函数是为了实现多态,所谓多态,简而言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”。例如:

class A
{
public:
    virtual void f()
    {
        cout<<"A::f() is called"<<endl;
    }
};

class B: public A
{
public:
    void f()
    {
        cout<<"B::f() is called"<<endl;
    }
};

int main(void)
{
    A *a = new B();
    a->f();   // 在这里,a虽然是指向A的指针,但是被调用的函数f()却是B的!
    return 0;
}

由于编写代码的时候并不能确定被调用的是基类的函数还是派生类的函数,所以被称为”虚”函数。一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的,这就是”动态联编“的概念。

纯虚函数

纯虚函数是在基类中声明的虚函数,它在基类中没有被实现,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加=0,例如:

virtual void func()=0;

定义纯虚函数是为了定义一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
正如设计模式中最根本的哲学问题:

Program to an interface, not an implementation.

注重接口,而不是实现,依赖接口,而不是实现。接口是抽象是稳定的,实现则是多种多样的。
需要说明的是,含有纯虚函数的类被称为抽象类,且不能被实例化。 因为在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

下面结合做的项目中的一个实例来阐述一下:
在锂电池Busbar焊缝检测中,焊缝种类多种多样,有圆型、椭圆型、S型等等,但检测项却基本一致,无非就是焊缝宽度、长度、变色、凹坑、突起等,这时候我们的基类就可以定义成抽象类,把每个检测项定义成纯虚函数,把每种检测项的方法交给子类去实现,其中每个子类就是不同的焊缝类型,下面为了简洁显示,仅以一种方法示意:

class HFBase
{
public:
    virtual void calcWidth()=0;
};

class HFCircle: public HFBase
{
public:
    void calcWidth()
    {
        cout<<"HFCircle::calcWidth() is called"<<endl;
    }
};

int main(void)
{
    HFBase *p = new HFCircle();
    p->calcWidth();   // 在这里,a虽然是指向A的指针,但是被调用的函数calcWidth()却是子类圆型焊缝的!
    return 0;
}