淘宝客网站做京东,上海将打造五大未来产业集群,设计素材网站0,网络域名ip查询文章目录 一、虚函数#xff08;Virtual Function#xff09;1.1 定义和作用1.2 实现原理1.3 示例代码1.4 虚函数的重写定义规则注意事项示例 1.5 基类和派生类的虚函数表**示例理解** 二、纯虚函数#xff08;Pure Virtual Function#xff09;2.1 定义和作用2.2 示例代码… 文章目录 一、虚函数Virtual Function1.1 定义和作用1.2 实现原理1.3 示例代码1.4 虚函数的重写定义规则注意事项示例 1.5 基类和派生类的虚函数表**示例理解** 二、纯虚函数Pure Virtual Function2.1 定义和作用2.2 示例代码 三、总结 在C面向对象编程中多态性是其三大特性之一封装、继承和多态。为了实现多态性C引入了虚函数Virtual Function和纯虚函数Pure Virtual Function的概念。本文将深入探讨虚函数和纯虚函数的原理和应用帮助读者更好地理解它们在C中的作用。 一、虚函数Virtual Function
1.1 定义和作用
虚函数是在基类中使用关键字 virtual 声明的成员函数它允许派生类对其进行重写Override实现运行时多态。当通过基类指针或引用调用虚函数时实际调用的是对象类型对应的派生类中的函数这个过程称为动态绑定Dynamic Binding或晚绑定Late Binding。
1.2 实现原理
虚函数的实现原理基于虚函数表Virtual Table简称VTable。每个使用虚函数的类都有一个虚函数表该表是一个函数指针数组存储了指向类的虚函数的指针。类的每个实例都包含一个指向其虚函数表的指针vptr通过这个指针可以找到并调用正确的虚函数实现。
当派生类覆盖重写基类的虚函数时派生类的虚函数表中相应位置的函数指针会被更新为指向派生类中的函数。如果派生类没有重写虚函数则派生类的虚函数表中会保留指向基类虚函数的指针。
1.3 示例代码
#include iostream
using namespace std;class Base {
public:virtual void show() {cout Base class show endl;}
};class Derived : public Base {
public:void show() override {cout Derived class show endl;}
};int main() {Base* b new Derived();b-show(); // 输出Derived class showdelete b;return 0;
}1.4 虚函数的重写
虚函数的重写Override是面向对象编程中实现多态性的一种方式。虚函数允许派生类根据需要改变或扩展基类中的行为。这里我们将详细探讨虚函数的重写包括它的定义、规则以及一些注意事项。
定义
虚函数重写指的是派生类中提供一个函数版本该版本与基类中具有相同名称、相同返回类型和相同参数列表的虚函数相匹配。通过这种方式派生类可以提供自己特定的实现替换或扩展基类的行为。
规则
函数签名必须匹配要重写基类中的虚函数派生类中的函数必须具有相同的名称、返回类型和参数列表。基类函数必须是虚函数只有虚函数可以被重写。如果基类中的函数不是虚函数派生类中相同签名的函数会隐藏而非重写基类中的函数。访问权限可以不同虚函数在派生类中的访问级别public、protected、private可以与基类中的不同但这会影响到函数的访问性。使用 override 关键字C11及以上虽然不是强制的但建议在派生类中重写虚函数时使用 override 关键字这有助于编译器检查函数签名是否正确匹配避免潜在的错误。
注意事项
析构函数应该是虚的如果一个类有可能被继承并且通过基类指针来删除派生类对象那么基类的析构函数应该是虚的。这确保了通过基类指针删除派生类对象时能够正确地调用派生类的析构函数。构造函数不能是虚函数在C中构造函数不能被声明为虚函数。因为构造函数是用来创建对象的而虚函数的调用需要通过对象的虚函数表这在对象构造阶段还未完全建立。使用 final 关键字防止进一步重写在某些情况下你可能希望禁止进一步重写某个虚函数。C11引入了final关键字可以用来阻止派生类重写特定的虚函数。
示例
#include iostreamclass Base {
public:virtual void print() const {std::cout Base class print function std::endl;}virtual ~Base() {} // 虚析构函数
};class Derived : public Base {
public:void print() const override { // 使用override确保正确重写std::cout Derived class print function std::endl;}
};int main() {Base* b new Derived();b-print(); // 输出Derived class print functiondelete b; // 正确调用派生类析构函数return 0;
}在上述示例中Derived 类重写了 Base 类中的 print 函数并且基类的析构函数被声明为虚函数确保了通过基类指针删除派生类对象时能够正确调用派生类的析构函数。
通过理解和正确应用虚函数的重写可以充分利用C的多态性设计出灵活且易于维护的面向对象程序。
1.5 基类和派生类的虚函数表
当涉及到继承时虚函数表vtable的处理方式会稍微复杂一些但关键点在于每个类都有自己的虚函数表而不是只有一个。这意味着如果有派生类继承自基类并且这些类中包含虚函数那么每个类将拥有各自独立的虚函数表。下面我们来详细解释这个过程。 基类在基类中编译器会为其创建一个虚函数表这个表包含了基类中所有虚函数的地址。如果派生类没有覆盖重写这些虚函数派生类对象的虚函数表会复制基类虚函数表中相应的条目。 派生类当派生类覆盖重写基类中的虚函数时派生类的虚函数表中对应位置的函数指针会被更新为指向派生类中的函数实现。如果派生类引入了新的虚函数这些新的虚函数也会被加入到派生类的虚函数表中。 多重继承在多重继承的情况下每个基类都会有自己的虚函数表。派生类对象会包含多个虚函数表指针每个指针指向对应基类的虚函数表。如果派生类覆盖了某个基类的虚函数那么相关基类虚函数表中的条目会被更新为指向派生类中的实现。
示例理解
考虑以下示例
class Base {
public:virtual void func1() { /* 实现 */ }virtual void func2() { /* 实现 */ }
};class Derived : public Base {
public:void func1() override { /* 新实现 */ }virtual void func3() { /* 新虚函数 */ }
};Base 类有自己的虚函数表包含 func1 和 func2。Derived 类有自己的虚函数表其中 func1 的条目会被更新为指向 Derived::func1func2 保持不变因为它没有被Derived重写并且会添加一个新的条目指向 func3。
二、纯虚函数Pure Virtual Function
2.1 定义和作用
纯虚函数是在基类中声明但不实现的虚函数其声明方式是在函数声明的结尾处添加 0。类中如果包含至少一个纯虚函数则该类成为抽象类Abstract Class不能实例化对象。
纯虚函数的主要作用是定义接口规范强制要求派生类必须实现这些函数从而实现接口的统一和标准化。
2.2 示例代码
#include iostream
using namespace std;class Shape {
public:virtual void draw() 0; // 纯虚函数
};class Circle : public Shape {
public:void draw() override {cout Drawing a circle endl;}
};int main() {Shape* shape new Circle();shape-draw(); // 输出Drawing a circledelete shape;return 0;
}三、总结
虚函数和纯虚函数是C实现多态性的关键机制。通过虚函数可以实现基类指针或引用调用派生类的成员函数而纯虚函数则定义了一个接口规范使得派生类必须实现特定的函数。这两种机制在C面向对象编程中发挥着至关重要的作用。
理解虚函数和纯虚函数的工作原理及其在C中的应用对于深入学习和掌握面向对象编程具有重要意义。希望本文能够帮助读者更好地理解这一概念提升C编程能力。