C++

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

2018-04-15  本文已影响0人  hello12qwerz

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();

上一篇 下一篇

猜你喜欢

热点阅读