C++中的函式重寫



函式是由包含指令的程式碼塊集合組成,用於執行特定任務。它旨在根據需要重複使用,從而將複雜的問題分解成更小、更容易管理的部分。

什麼是C++中的函式重寫?

函式重寫是面向物件程式設計的一個概念,它允許派生類重新定義已在基類中定義的函式。

這裡方法的名稱和引數保持不變,但是派生類會更改其行為以滿足其特定需求。

示例

讓我們考慮這兩個函式;一個是基類 (a),另一個是派生類 (b),函式 (c) 是 main(),我們在其中實現重寫 -

函式 (a)

class base {
public:
   void notice( )
   cout << "This is my Base Class" ;
}

函式 (b)

class derived: public base {
   public:
      void notice( )
      cout << "This is my Derived Class";
}

函式 (c)

void main ( ) {
   // creating an object for base class and calling it
   base b;
   b.notice( );   
   // creating an object for derived class and calling it 
   derived d ;
   d.notice( );    
}

重寫解釋

  • 在這裡,我們分別建立了“函式 (a) 和函式 (b)”的基類和派生類的物件,並像顯示的那樣在函式 (c) 中呼叫它們,“b.notice() 和 d.notice()”。
  • 在這種情況下,將首先執行派生類 d.notice(),因為它代表函式的最新或更新版本。
  • 但是,如果我們像在函式 (c) 中顯示的那樣建立基類的物件“b.msg()”並呼叫它,它將使用基類的原始版本。

簡而言之,當在派生類中重新定義基類的功能時,就會發生函式重寫。當建立派生類的物件時,它將呼叫來自派生類的更新後的函式,這意味著基類函式 (a) 被派生類函式 (b) 重寫。

函式重寫是面向物件程式設計中的一個重要概念,它支援多型性和動態繫結。

函式重寫的示例

下面是一個簡單的示例,說明重寫是如何工作的

#include <iostream>
using namespace std;

// Base class
class Shape {
   public:
      // Virtual method to be overridden
      virtual void draw() const {
         cout << "Drawing a shape" << endl;
      }
};

// Derived class Circle
class Circle : public Shape {
   public:
      // Overriding the base class method
      void draw() const override {
         cout << "Drawing a circle" << endl;
      }
};

// Derived class Square
class Square : public Shape {
   public:
      // Overriding the base class method
      void draw() const override {
         cout << "Drawing a square" << endl;
      }
};

// Main function
int main() {
   Shape* shapePtr;
   Circle circle;
   Square square;

   // Point to Circle and call draw()
   shapePtr = &circle;
   shapePtr->draw();   // Outputs: Drawing a circle

   // Point to Square and call draw()
   shapePtr = □
   shapePtr->draw();   // Outputs: Drawing a square

   return 0;
}

輸出

Drawing a circle
Drawing a square

函式重寫與函式過載

雖然函式重寫和函式過載是C++面向物件程式設計的重要關鍵概念,但它們都服務於不同的目的。

函式重寫允許派生類為其先前定義的基類獲得方法的新實現,因為它們具有不同的作用域(基類和派生類),它在執行時多型性(動態繫結)中得到解決,它只發生在繼承存在的情況下,並且只能重寫一次,而執行速度相對較慢。

而函式過載使您能夠在相同的作用域內建立具有相同名稱但引數列表不同的多個函式。它在編譯時多型性(靜態繫結)中得到解決,繼承的存在並不重要,這些函式可以多次過載,並且執行速度相對較快。

高階重寫概念

以下是涵蓋高階重寫概念的其他子主題列表 -

1. 虛解構函式

虛解構函式確保當透過基類指標刪除物件時,將執行派生類的解構函式。使用虛解構函式的函式重寫透過確保透過基類指標正確刪除物件來避免資源洩漏和不可預測的行為。

示例

#include <iostream>
using namespace std;

class BaseClass {
   public:
      virtual ~BaseClass() {  // Virtual destructor
         cout << "BaseClass destructor" << endl;
      }
};

class DerivedClass : public BaseClass {
   public:
      ~DerivedClass() override {  // Overriding destructor
         cout << "DerivedClass destructor" << endl;
      }
};

int main() {
   BaseClass* a = new DerivedClass();
   // Calls DerivedClass's destructor followed
   // by BaseClass's destructor
   delete a;
   return 0;
}

輸出

DerivedClass destructor
BaseClass destructor

2. 協變返回型別

協變返回型別允許派生類重寫方法並返回比基類方法更具體的型別。這意味著派生類可以返回指向更派生型別的指標或引用,而不僅僅是基型別。函式重寫提高了面向物件程式設計的靈活性和精度。

注意

在派生類中,返回型別必須是指向派生自基類返回型別的型別的指標或引用。

示例

#include <iostream>
using namespace std;
class Vehicle {
   public:
      // Final method
      virtual void honk() final {
         cout << "Vehicle honk: Beep beep!" << endl;
      }
};

class SportsCar : public Vehicle {
   // Cannot override honk() here
};

int main() {
   Vehicle* v = new SportsCar();
   v->honk(); // Calls Vehicle's honk() method
   delete v;
   return 0;
}

輸出

Vehicle honk: Beep beep!

3. 重寫和 final 關鍵字

`final` 關鍵字阻止對類的進一步子類化或方法的重寫。

使用 `final` 關鍵字的函式重寫非常重要,因為它保證了類或方法不能被進一步更改或擴充套件。

示例

#include <iostream>
using namespace std;

class Subject {
   public:
      // Final method
      virtual void examType() final {
         cout << "This subject has a written exam." << endl;
      }
};

class Math : public Subject {
   // Cannot override examType() here
};

int main() {
   Subject* s = new Math();
   s->examType(); // Calls Subject's examType() method
   delete s;
   return 0;
}

輸出

This subject has a written exam.

4. 虛擬繼承

C++ 中的虛擬繼承解決了多重繼承中出現的問題,特別是菱形問題。它確保當一個類繼承自幾個具有共同祖先的基類時,只建立一個該共同基類的例項。

虛擬繼承確保當多個派生類在層次結構中共享該基類時,只使用一個基類的副本。

示例

#include <iostream>
using namespace std;

class Base {
   public:
      void present() { cout << "Display from Base class" << endl; }
};

class A : virtual public Base { };
class B : virtual public Base { };

class Final : public A, public B {
   public:
      void get() { cout << "Display from Final class" << endl; }
};

int main() {
   Final obj;
   // Displays: Display from Base class
   obj.present();
   // Displays: Display from Final class
   obj.get();     
   return 0;
}

輸出

Display from Base class
Display from Final class

函式重寫的優點

1. 多型性

重寫透過允許不同派生類的物件被視為基類的例項來實現多型性。這允許在執行時進行動態方法繫結,其中根據物件型別選擇正確的函式實現,從而提高靈活性和適應性,使其成為多型性的基本組成部分。

2. 程式碼可重用性

開發人員可以透過繼承基類的方法並在派生類中自定義它們來利用現有程式碼。這種方法促進了更精簡和組織良好的程式碼結構。

3. 可維護性

重寫透過將各種功能封裝在不同的類中來促進模組化設計。這種方法簡化了程式碼的理解、維護、更新和擴充套件。

4. 設計模式

重寫在模板方法模式中起著關鍵作用,它在基類中定義演算法的整體結構,同時允許子類重寫特定步驟。

策略模式利用重寫來封裝各種演算法並允許在執行時進行交換。

5. 記憶體管理

在使用繼承和動態記憶體分配時,虛解構函式對於正確的記憶體管理至關重要。在派生類中重寫解構函式確保基類和派生類分配的資源得到正確的釋放,從而防止記憶體洩漏並確保資源得到乾淨的釋放。

廣告