C++语法系列之14-- virtual总结

1 动态绑定

在C++中,默认不会触发动态绑定,如果需要触发动态绑定,那么就需要:
1)将函数指定为虚函数;
2)通过基类的指针或引用调用该函数

class Base {
   public:
      virtual void f() {
         cout <<"Base f()" << endl;
      }
     ~Base() {}
}

class Derived {
   public:
      void f() {
         cout <<"Derived f()" << endl;
      }
      ~Derived() {}
}

int main() {
   Base b; 
   b.f();//Base f()

   Derived d;
   d.f();//Derived f()

   Base* bp = new Derived();
   bp->f();//Derived f()动态绑定,如果不是virtual,那么输出会是Base f()
}

注意以上代码中:如果f()不是virutal函数,那么bp->f(),不会动态绑定,执行的将是Base的f()。


class Base {
public:
    Base() {
        cout <<"Base ctor" << endl;
    }
    void f() {
        cout <<"Base f()" << endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        cout << "Derived ctor" << endl;
    }
    
    void f() {
        cout <<"Derived f()" << endl;
    }
};

int main(int argc, const char * argv[]) {
    Base* bp = new Derived();
    bp->f();//由于不是virtual,执行的将是Base::f()
}

2 基类指定为virtual,子类都会是virtual

3 virutal 析构函数

如果在类继承层次结构上要正确的释放资源,调用析构函数,那么必须将析构函数都声明为virutal

class Base {
   public:
     ~Base() {
      cout << "~Base()"  << endl;
    }
}

class Derived {
   public:
      void f() {
         cout <<"Derived f()" << endl;
      }
      ~Derived() {
        cout <<"~Derived()" << endl;
      }
}

int main() {
      Base* bp = new Derived();
      delete bp;
 }

运行结果:

~Base()

由于析构函数不是virtual,子类的析构函数不会被调用。这样就出现问题了。所以建议对所有的类,析构函数都设置为virtual。

4 纯虚函数

纯虚函数类似java中的interface或者abstract class抽象类的效果

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

带有纯虚函数的类,不能被实例化,通常作为基准接口来使用。子类覆写纯虚函数才可以实例化。

5 虚继承

C++中多重继承,会出现交叉继承的问题(也就是菱形继承结构)。


class Base {
public:
    Base() {
        cout <<"Base ctor" << endl;
    }
    virtual void f() {
        cout <<"Base f()" << endl;
    }
};

class Derived1 : virtual  public Base {
public:
    Derived1() {
        cout <<"Derived1 ctor" << endl;
     }
  
};

class Derived2 : virtual public Base {
public:
    Derived2() {
        cout <<"Derived2 ctor" << endl;
    }
  
};

class CommonDerived:  public Derived1,  public Derived2 {
    
};

int main(int argc, const char * argv[]) {
    CommonDerived c;
    c.f();//这里可以编译通过,因为继承的时候,使用了virtual,同时Derived1/Derived2也没有覆写f()
  
}

上面的代码可以编译通过:
1)因为Derived1/Derived2都 虚继承于Base;
2)Derived1/Derived2/CommonDerived都没有覆写f(),只要有一个覆写,那么都无法编译通过;
3)此时c.f()等价于 c.Base::f()/c.Derived1::f()/c.Derived2::f()/c.CommonDerived::f();

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • C++中子类与超类的方法可以有不同的默认参数,但是使用的默认参数取决于声明的变量类型,而不是底层实际的对象类型。 ...
    hello12qwerz阅读 1,833评论 0 0
  • TODO
    hello12qwerz阅读 1,248评论 0 0
  • 两千五百多公里的自驾旅程即将结束,用这篇文字记录路上的一些体会。 秋高气爽的十一黄金周,不在高速上经历一番刻骨铭心...
    阿台Ruby阅读 1,826评论 0 0
  • 教育界曾经有一个课题是:“你的孩子,如果被别的孩子打了,你会教育孩子怎么办?” 1.用合适的方式告诉长辈。2.要尽...
    海伦不哭阅读 747评论 0 0
  • 一公里的路等了二十分钟公交,还坐过站了,一个人,无所谓,夜色真美,东西搬完了。
    chaosii阅读 1,157评论 0 0