c++筆記:虛函數必要但易忘的一些性質

前言:

老師留了一個做業,就是對虛函數的使用,沒有什麼難度,但就是對虛函數的性質用來用去,搞得我一次又一次的查資料,可能這也是每一個人必走的吧,因此我準備分享一下我認爲學習c++虛函數裏面須要注意的性質以及用法。c++

 

總結:其實虛函數總結就一句話:使用基類的指針,指向派生類對象,調用虛函數的時候,最後調用的是派生類的函數。

 

一:動態綁定:

只有調用基類的指針引用調用虛函數時,纔會發生動態綁定。ide

  • 例如:
Derived d;//Derived是派生類,Base是基類
Base *ptr=&d;//積累指針指向派生類的對象
Base &ref=d;//基類引用做爲派生類的別名
Base b=d;//調用Base的拷貝函數用d構造b

 

  • 效果:
    ptr->函數名,調用派生類中的對應函數
    ref.函數名,掉用派生類中的對應函數
    b.函數名,調用基礎類中的對應函數
    

      

 

 

二:靜態動態連編:針對基類派生類有同名函數

  • 經過派生類對象訪問同名函數。這是靜態連編函數

  • 經過基類對象的指針訪問同名函數。這也是靜態連編學習

  • 經過基類對象的指針或引用訪問同名虛函數,這是動態連編(老師喜歡考的)this

    class P{public:f(){.....}};//father
    class C:public P{public:f(){....}};//son
    main(){
        P* ptr;
        P p;
        C c;
        ptr=&p;
        ptr->f();//調用P::f()
        
        ptr=&c;
        ptr->f();//調用P::f()
    }
    

      

 

注意:要是沒有vitural,指針什麼類型就調用什麼類型spa

 

 

三:overeide和final:(這老忘,仍是多記記纔是)

  • override顯式聲明覆寫
class A {
public:
  virtual void foo() {}
  void bar() {}
};
 
class B : public A {
public:
  void foo() const override { // 錯誤: B::foo 不覆寫 A::foo
  }                           // (簽名不匹配)
  void foo() override;   // OK : B::foo 覆寫 A::foo
  void bar() override {} // 錯誤: A::bar 非虛
};
 
void B::foo() override {// 錯誤: override只能放到類內使用
}

  

 

 

  • 還有一種覆寫方式,這好像是以前學習到的一個知識點,忘了,從新鞏固一下。。。
    class Animal
    {
    public:
    	Animal();
    	~Animal();
    	virtual Animal& speak() {//能夠只在父類中定義vitural
    		return *this;//注意必定要在每個覆寫的後面加上這個返回
    	}
    
    };
    
    class Dog:public Animal
    {
    public:
    	Dog();
    	~Dog();
    	Dog& speak() {
    		cout << "wang" << endl;
    		delete this;
    		return *this;
    	}
    };
    void test(Animal& p){//注意:覆寫以後暫時尚未效果,必需要定義一個void函數來調用,固然是用下面的方式來調用啦
        p.speak();
    }
    

      

 

 

  • final 顯式聲明禁止覆寫
 

 

struct Base {
    virtual void foo();
};
 
struct A : Base 
{ 
    void foo() final; // A::foo 被覆寫且是最終覆寫
    void bar() final; // 錯誤:非虛函數不能被覆寫或是 final
};
 
struct B final : A // struct B 爲 final,不能被繼承
{
    void foo() override; // 錯誤: foo 不能被覆寫,由於它在 A 中是 final
};

  

 

 

四:抽象類:

特徵:指針

  • 抽象類不能實例化。對象

  • 抽象類能夠包含抽象方法和抽象訪問器。blog

  • 從抽象類派生的非抽象類必須包括繼承的全部抽象方法和抽象訪問器的實際實現。繼承

  • 必須是派生類來實現,而不是讓基類實現

 

 

五:動態轉換dynamic_cast:

使用狀況:下面會提到上轉和下轉,與其相似

 

 

// A function for displaying a Shape object
void printObject(Shape &shape)
{
  cout << "The area is " 
       << shape.getArea() << endl;
    
    //這裏就是判斷是否是該類型是否是要轉換的類型,固然必須用到指針
  Shape *p = &shape;
  Circle *c = dynamic_cast<Circle*>(p);
  // Circle& c = dynamic_cast<Circle&>(shape); 
  // 引用轉換失敗則拋出一個異常 std::bad_cast
  if (c != nullptr) // 轉換失敗則指針爲空
  {
    cout << "The radius is " 
         << p1->getRadius() << endl;
    cout << "The diameter is " 
         << p1->getDiameter() << endl;
  }
}

  

 

六:基類和派生類向上和向下轉換:(很重要,課設裏面會常常用到)

  • 上轉:upcasting : Assigning a pointer of a derived class type to a pointer of its base class type (將派生類類型指針賦值給基類類型指針)

    Shape* s = nullptr;
    Circle *c = new Circle(2);
    s = c; //OK,隱式上轉
    

      

 
  • 下轉:downcasting : Assigning a pointer of a base class type to a pointer of its derived class type. (將基類類型指針賦值給派生類類型指針)

Shape* s = new Circle(1);
Circle *c = nullptr;
c = dynamic_cast <Circle*> (s); //顯式下轉

 

好了,上面就是我對c++虛函數一些性質的簡單總結和用法

相關文章
相關標籤/搜索