首頁  >  問答  >  主體

关于C++的虚方法问题

我在看到C++的虚方法 的时候,怎么突然有种多此一举的感觉。比如有个基类 Class Mammal{};然后又有个派生类 Class Dog : public Mammal {};然后我弄个对象出来 Dog Fido; 按道理来说 Fido这个条狗 就能继承 Mammal这个类 public 里面的所有方法(除了Dog类里面被覆盖的)。

然后我们再来看下 虚方法这个东东。要让虚方法 virtual 起作用, 那么new 出来的 对象 必须要用其基类的指针变量来接收 ,比如: Mammal * Fido = new Dog ;等到 用 Fido来调用方法的时候 首先是先去Mammal里面找 如果找到的函数 是个虚函数,那么久忽略掉这个函数 用Dog(Dog 里面有个同名的函数) 类里面的函数。

当我看到 虚函数的这个作用的时候,我感觉 不都是继承嘛! 还搞这么多花样,在我目前的学习阶段,我主观上没发现该虚方法有什么好处。 大家来谈谈看撒!

伊谢尔伦伊谢尔伦2714 天前903

全部回覆(5)我來回復

  • 天蓬老师

    天蓬老师2017-04-17 14:37:06

    虛函數用於多態。例如在遊戲中,所有的玩家和敵人都可以繼承同一個遊戲角色類,其內部的更新函數和渲染函數就是虛函數。用一個基類指針數組來儲存這些不同的玩家和敵人,更新和渲染時只需一個for循環就好了,省去了很多功夫。

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-17 14:37:06

    設想一下如下場景:
    你有一個UI庫,有很多組件,如TextEditor,Button等,它們都是以UIBase為基類的;
    現在,你要遍歷所有的組件,找出所有類型為Button的組件

    那麼使用虛方法就能很輕鬆地實現:
    首先為UIBase添加一個虛方法char* GetType()(在這個例子中,其實添加為純虛方法更合適一點),然後每個子類都重寫GetType(),例如Button類別就重寫為char* GetType(){return "Button";}

    由於我可以用基類指針保存子類對象,那麼我只要維護一個數組UIBase *a[],每次新建元素的時候都加入到a當中,那麼回到我的需求上來,只要執行for(k in a) if(k->GetType()=="Button"){...}

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-17 14:37:06

    C++虛擬函式: 多態的實作必不可少一部分。 多態? -> 程式碼復用的最高境界,工程意義,呼叫未來。

    C++沒有接口, 如何實作? 純虛函數介面類別。

    虛析構, 介面的封裝與設計。

    原理:動態連結

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 14:37:06

    舉例:

    比如說,如果Mammal和Dog都定義了虛函數 virtual void do()。此時你定義了一個函數

    void fun(Mammal * ani)
    {
        ani->do();
    }
    
    Mammal * ani = new Dog();
    fun(ani);

    那麼此時,參數可以傳入Mammal或Dog物件指標。如上一段程式碼,由於ani指標所指向的對象,實際型別是Dog,所以當呼叫ani->do()時,由於do是虛擬方法,所以會呼叫Dog::do()。

    但是如果do不是虛方法,那麼ani->do()實際執行的將是Mammal::do();

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-17 14:37:06

    關於這些東西,在《深度探索C++物件模型》這本書裡面有比較詳細的描述。
    虛函數涉及到的是運行時綁定,非虛函數是編譯時綁定。
    舉個例子。

    #include <iostream>
    using namespace std;
    class A{
      public:
      void f1(){cout<<"A::f1"<<endl;}
      virtual void f2(){cout<<"A::f2"<<endl;}
    };
    
    class B:public A{
      public:
      void f1(){cout<<"B::f1"<<endl;}
      virtual void f2(){cout<<"B::f2"<<endl;}
    };
    
    class C:public A{
      public:
      void f1(){cout<<"C::f1"<<endl;}
      virtual void f2(){cout<<"C::f2"<<endl;}
    };
    
    int main()
    {
      A* p = 0;
      char t;
      cin>>t;
      switch(t){
        case 'B':
        case 'b':
          p = new B;break;
        case 'C':
        case 'c':
          p = new C;break;
        case 'A':
        case 'a':
        default:
          p = new A;
      }
      p->f1();    // 这里将始终输出 A::f1,编译时候就确定了
      p->f2();    // 这里是在运行时才能确定的
                  // p指向的对象中包含虚函数指针,指向虚函数表
                  // 调用f2的时候是根据这个指针去确定使用哪一个的
    }

    回覆
    0
  • 取消回覆