跳转至

虚函数

class Instrument {
public:
    virtual void play() {
        cout << "virtual paly" << endl;
    }
};

class Wind: public Instrument {
public:
    void play() {
        cout << "paly" << endl;
    }
};

void virtualTest() {
    Instrument *i = new Wind();
    i->play();//打印Wind的paly
}

重载和重写

同名的函数 继承的时候 会把基类的函数隐藏

例:

  • 基类
  • 有三个虚函数

  • 子类(继承基类)

  • 重写继承的虚函数,函数是一样的(返回值、参数、函数名)。
  • 如果函数不一样(返回值类型不一样),C++会检查报错。
  • 如果函数不一样(返回值和参数类型都不一样),这个函数就是重新定义该函数,把基类的函数隐藏了,就不能再调用基类的方法了。已经隐藏基类的了。子类向上转型,就不能调用子类的方法了。可以调用基类里的被隐藏的虚函数。

调用子类的函数,如果子类没有的话就会调用基类的虚函数。子类有重写虚函数的话就调用子类自己的虚函数。

子类重新定义了基类的函数,子类就调不了基类的函数了,基类中的被隐藏了。但是如果向上转型,就调不了子类的函数了,只能调用基类的。

继承下来的虚函数重写,改变了返回值的类型,这样是错误了,返回值类型不允许改变。有一个特例:如果原来的返回值类型和重写的返回类型是继承关系。用指针或者引用,之前返回的是是一个class,继承返回的是子类。

虚函数重写 的时候

  1. 照原样,什么都不改,没有问题
  2. 发生了改变 返回类型 参数 改变 可能不是重写虚函数了,可能是把原来的虚函数重写,原来的函数就隐藏。(一定情况下,返回类型可以改变)

虚函数做多态重写的时候,尽量原样重写,不要做任何改变。这样就简单,不会有问题(隐藏或者出错)。

构造函数不能是虚函数

创建一个对象的时候要把自己的成员,还有它的父类,父类的成员,祖父类等等都构造出来。

构造的时候首先构造最顶层的根,然后再构造儿子(先构造儿子的成员),最后构造孙子,先把孙子的成员构造出来,再构造孙子自己。

构造函数都是用来构造当前的对象。

析构函数必须是虚函数

析构和构造函数完全相反,

delete会调用析构函数,如果执行基类的析构函数,基类的是虚函数,实际上调用的是子类的析构函数,子类会逐一析构,一层层向上析构。如果基类析构函数不是虚函数,则会调用基类的析构函数,只会析构基类,子类的都没有析构。所以析构函数必须是虚的

C++编程,如果类不需要继承,那么所有的函数都不需要虚函数。

当做成继承的时候,所有的函数成员最好都做成虚函数,除了构造函数。

只要有一个虚函数,则析构函数就要做成虚的。

做成虚的,C++会给它配一个虚表。

析构函数做成纯虚的

有的时候析构函数做成纯虚的:

基类是做接口的,不能构造对象,如果不是纯虚的就可以构造对象。

只要有一个是纯虚的,那么类就是抽象类,只能做接口。不能构造对象。

基类析构函数可以做一个纯虚定义。析构的时候会调用子类的析构函数,在子类里会调用基类的析构函数。

子类的析构函数可以不写,C++会自动添加,基类的析构函数必须得写。

析构函数中的虚机制

例;

基类虚的析构函数,析构函数里面调用了f,f是基类中的一个虚函数。

子类调用f,实际上调用的还是基类的f。因为析构的时候,子对象被析构了,所以只能调用基类的函数了。

析构和构造顺序是相反的。