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. 内存管理

在使用继承和动态内存分配时,虚析构函数对于正确的内存管理至关重要。在派生类中重写析构函数确保基类和派生类分配的资源得到正确的释放,从而防止内存泄漏并确保资源得到干净的释放。

广告