关于虚函数的总结

虚函数可以实现多态特性,因此在设计模式中很有用,配合继承的特性可以提供很好的解决方案
1.impure virtual

  • 基类指定接口和缺省的实现方式,派生类重载基类中的虚函数,定义自己的实现方式,然后通过基类指针指向从而实现多态。
class Man
{
public:
    virtual void sayHello()
    {
        std::cout << "Hello" << std::endl;
    }
    virtual void walk()
    {
        std::cout << "walk" << std::endl;
    }
};
class Teacher:public Man
{
public:
    void sayHello()
    {
        std::cout << "Hello,Teacher" << std::endl;
    }

};
Man m;
m.sayHello();
Man *pm = new Teacher;
pm->sayHello();
  • 虚函数可以不在子类里重载

2.pure virtual

  • 定义了纯虚函数的类叫抽象基类,而抽象基类负责定义接口,后续的类可以覆盖并且必须重新定义实现该函数,抽象类不可以创建对象
class Airplane
{
public:
    virtual void fly() = 0;

};

class Model1 :public Airplane
{
    void fly() { std::cout << "Model1 fly" << std::endl; }
};
class Model2 :public Airplane
{
    void fly() { std::cout << "Model2 fly" << std::endl; }
};
  • 抽象类纯虚函数一般不会有实现部分,但有时也可以有,主要是为了子类同时可以继承接口和一部分缺省实现
class Airplane
{
public:
    virtual void fly() = 0;

};
void Airplane::fly()
{
    std::cout << "default fly" << std::endl;
}
class Model1 :public Airplane
{
    void fly() { std::cout << "Model1 fly" << std::endl; }
};
class Model2 :public Airplane
{
    void fly() { std::cout << "Model2 fly" << std::endl; }
};
class Model3 :public Airplane
{
    void fly() { Airplane::fly(); }
};

3.虚基类

  • 多继承时很容易产生命名冲突,因此,当一个基类被声明为虚基类后,即使它成为了多继承链路上的公共基类,最后的派生类中也只有它的一个备份。
class CBase { }class CDerive1:virtual public CBase{ }class CDerive2:virtual public CBase{ }class CDerive12:public CDerive1,CDerive2{ }//则在类CDerive12的对象中,仅有类CBase的一个对象数据
  • 虚基类构造函数的参数必须由最新派生出来的类负责初始化(即使不是直接继承),虚基类的构造函数先于非虚基类的构造函数执行。
/**//************************************************************************
* 混合继承:多基类继承与多重继承
************************************************************************/
#include <IOSTREAM.H>
//基类
class CBase
...{
protected:
    int a;
public:
    CBase(int na)
    ...{
        a=na;
        cout<<"CBase constructor! ";
    }

    ~CBase()...{cout<<"CBase deconstructor! ";}
};

//派生类1(声明CBase为虚基类)
class CDerive1:virtual public CBase
...{
public:
    CDerive1(int na):CBase(na)
    ...{
        cout<<"CDerive1 constructor! ";
    }

    ~CDerive1()...{cout<<"CDerive1 deconstructor! ";}

    int GetA()...{return a;}
};

//派生类2(声明CBase为虚基类)
class CDerive2:virtual public CBase
...{
public:
    CDerive2(int na):CBase(na)
    ...{
        cout<<"CDerive2 constructor! ";
    }
    ~CDerive2()...{cout<<"CDerive2 deconstructor! ";}
    int GetA()...{return a;}
};

//子派生类
class CDerive12:public CDerive1,public CDerive2
...{
public:
    CDerive12(int na1,int na2,int na3):CDerive1(na1),CDerive2(na2),CBase(na3)
    ...{
        cout<<"CDerive12 constructor! ";
    }
    ~CDerive12()...{cout<<"CDerive12 deconstructor! ";}
};
void main()
...{
    CDerive12 obj(100,200,300);
    //得到从CDerive1继承的值
    cout<<" from CDerive1 : a = "<<obj.CDerive1::GetA();
    //得到从CDerive2继承的值
    cout<<" from CDerive2 : a = "<<obj.CDerive2::GetA()<<endl<<endl;
}

此代码出处
4.虚析构函数的妙用
对于基类指针指向派生类时,delete该指针应该相应的执行该子类的析构函数,所以需要将基类定义成virual

class Base{
public:
    virtual ~Base()=default;
}

5.虚函数表

  • 每个含有虚函数的类有一张虚函数表,表中每一项是一个虚函数的地址, 也就是说,虚函数表的每一项是一个虚函数的指针。
    6.非虚函数接口的实现
    ….

7.总结

  • 虚函数带来的多态效应在实际中非常有用,一般C++的项目设计派生时,尽量将函数加上virtual,这样子类可以更加灵活
  • 纯虚函数关注的是接口继承和默认行为,可以防止被实例化
  • -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值