网站建设科目,怎么制作一个自己的网站,做红酒的网站有哪些,做分析报表的网站C笔记之实现多态的所有方法 文章目录 C笔记之实现多态的所有方法1.C中多态是是什么#xff1f;请用简洁准确的话描述2.虚函数实现多态2.1.虚函数#xff08;Virtual Functions#xff09;2.2.纯虚函数#xff08;Pure Virtual Functions#xff09;2.3.虚析构函数#xf…C笔记之实现多态的所有方法 文章目录 C笔记之实现多态的所有方法1.C中多态是是什么请用简洁准确的话描述2.虚函数实现多态2.1.虚函数Virtual Functions2.2.纯虚函数Pure Virtual Functions2.3.虚析构函数Virtual Destructor2.4.虚函数表Virtual Function Table 3.函数指针Function Pointers4.模板Templates5.达到多态性的效果5.1.接口类Interface Classes5.2.可调用对象Callable Objects 6.C中函数重载是不是一种实现多态的方法7.虚函数表8.虚函数指针9.抄自别的文章——C中虚函数的实现虚函数表vtable虚函数指针vptr多态的工作机制注意事项 1.C中多态是是什么请用简洁准确的话描述 2.虚函数实现多态
在C中实现多态性polymorphism的主要方法是通过使用虚函数virtual functions。下面是C中实现多态性的方法
2.1.虚函数Virtual Functions
在基类中声明一个虚函数在派生类中可以对该函数进行重写。通过使用指向基类的指针或引用来调用该函数时实际上会根据对象的实际类型调用相应的派生类函数。这是C中最常见的多态性实现方式。
class Base {
public:virtual void polymorphicFunction() {// Base class implementation}
};class Derived : public Base {
public:void polymorphicFunction() override {// Derived class implementation}
};2.2.纯虚函数Pure Virtual Functions
纯虚函数是在基类中声明的虚函数但没有提供实际实现。派生类必须重写这些纯虚函数才能被实例化。类包含纯虚函数的类称为抽象类抽象类不能被实例化只能被继承。
class AbstractBase {
public:virtual void pureVirtualFunction() 0; // Pure virtual function
};class Derived : public AbstractBase {
public:void pureVirtualFunction() override {// Derived class implementation}
};2.3.虚析构函数Virtual Destructor
如果基类需要被其他类继承而且基类中有使用了new关键字动态分配内存的成员那么必须在基类中将析构函数声明为虚函数以确保在删除指向派生类对象的基类指针时能正确调用派生类的析构函数避免内存泄漏。
class Base {
public:virtual ~Base() {// Base class destructor}
};class Derived : public Base {
public:~Derived() override {// Derived class destructor}
};2.4.虚函数表Virtual Function Table
C编译器通过在包含虚函数的类中插入一个虚函数表来实现多态性。该表包含了类的虚函数地址允许在运行时动态调用正确的函数实现。
这些是C中实现多态性的主要方法。虚函数和纯虚函数是最常见和推荐的实现方式。
除了使用虚函数C中还有另外两种实现多态性的方法
3.函数指针Function Pointers
使用函数指针可以在运行时实现多态性。通过定义一个指向函数的指针然后在派生类中赋值为相应的函数可以实现动态调用不同的函数实现。
class Base {
public:void nonPolymorphicFunction() {// Base class implementation}
};class Derived : public Base {
public:void polymorphicFunction() {// Derived class implementation}
};int main() {Base* ptr;Derived derivedObj;ptr derivedObj;// Function pointer for polymorphic behaviorvoid (Base::*functionPtr)() Base::nonPolymorphicFunction;(ptr-*functionPtr)(); // Calls Base::nonPolymorphicFunction()functionPtr Base::polymorphicFunction;(ptr-*functionPtr)(); // Calls Derived::polymorphicFunction()return 0;
}4.模板Templates
C的模板也可以实现多态性特别是通过模板类和模板函数。使用模板参数可以在编译时根据不同的参数类型生成不同的代码从而实现多态性。
template typename T
class PolymorphicClass {
public:void polymorphicFunction() {// Common implementation for all types}
};template
void PolymorphicClassint::polymorphicFunction() {// Implementation specific to int
}int main() {PolymorphicClassfloat floatObj;PolymorphicClassint intObj;floatObj.polymorphicFunction(); // Calls the common implementationintObj.polymorphicFunction(); // Calls the specialization for intreturn 0;
}虽然虚函数是实现多态性的最常见和推荐方法但是这两种方法也提供了额外的灵活性特别是在特定情况下可以使用函数指针来实现更高度定制化的多态性。模板也可以在编译时优化代码提高性能。但这些方法相对较少使用主要是因为虚函数在C中提供了更为直接和方便的多态性实现。
5.达到多态性的效果
除了前面提到的虚函数、函数指针、模板和虚拟继承C中没有其他内置的语言特性来直接实现多态性。这些是C中主要的方法来实现多态行为。
然而C是一门非常灵活的语言允许通过各种技术和设计模式来实现更高级的多态性。下面列举了一些可能的方法虽然它们不是直接的语言特性但仍然可以达到多态性的效果
5.1.接口类Interface Classes
C中没有内置的接口类概念但可以通过定义只包含纯虚函数的抽象类来模拟接口。其他类可以继承这个接口类并实现其纯虚函数从而实现多态性。
class Interface {
public:virtual void doSomething() 0;
};class ConcreteClass : public Interface {
public:void doSomething() override {// Implementation in ConcreteClass}
};5.2.可调用对象Callable Objects
C中的函数对象Functor或Lambda表达式可以作为可调用对象使得可以在运行时动态决定调用哪个函数从而实现多态性。
#include functionalclass Base {
public:virtual void polymorphicFunction() {// Base class implementation}
};class Derived : public Base {
public:void polymorphicFunction() override {// Derived class implementation}
};int main() {Base* ptr new Derived;// Using std::function as a callable object for polymorphic behaviorstd::functionvoid(Base*) func [](Base* obj) { obj-polymorphicFunction(); };func(ptr); // Calls Derived::polymorphicFunction()return 0;
}这些方法都是在C中模拟多态性的常见手段。请注意这些方法可能需要更多的代码和额外的管理相比于虚函数的直接性和简洁性可能并不是首选方案。因此虚函数仍然是实现多态性的最常用和推荐的方式。
6.C中函数重载是不是一种实现多态的方法
在严格意义上C中的函数重载并不被认为是一种实现多态的方法。
函数重载是一种在同一个作用域内定义多个同名函数但参数列表不同的机制。当调用这个函数时编译器会根据传递的参数类型或数量来决定调用哪个具体的函数。函数重载主要用于提供一种方便的方式让程序员能够使用相同的函数名处理不同类型或不同数量的数据以增强代码的可读性和灵活性。
虽然函数重载使得代码更具灵活性和可读性但它并没有实现多态性。多态性涉及到在运行时选择调用哪个函数的能力这通常通过虚函数来实现允许根据对象的实际类型来调用适当的函数。
在函数重载中函数调用在编译时就已经确定了不会根据对象的实际类型在运行时决定调用哪个函数。相比之下使用虚函数时函数调用是在运行时动态绑定的允许在处理基类指针或引用时调用派生类中的函数实现实现了真正的多态性。
总结来说函数重载和多态性是不同的概念。函数重载是一种静态多态而多态性通常指动态多态它通过虚函数实现允许在运行时根据对象的实际类型来选择调用适当的函数。
7.虚函数表
虚函数表Virtual Function Table通常简称为虚表是C中实现多态性的关键机制之一。它是一个用于存储虚函数地址的表格每个具有虚函数的类都会在内存中维护一个虚函数表。
虚函数表的工作原理如下
虚函数表是一个包含指向虚函数的指针的数组。每个虚函数在表中占据一个槽位。对于每个包含虚函数的类编译器会在类的布局中插入一个指向其虚函数表的指针通常称为虚函数指针vptr。当一个对象被创建时它的虚函数指针被初始化为指向该类的虚函数表。调用虚函数时实际上是通过对象的虚函数指针查找虚函数表然后调用相应的虚函数。
这个机制使得基类指针或引用可以在运行时动态地调用派生类中适当的虚函数从而实现多态性。
以下是一个简化的示例来说明虚函数表的概念
class Base {
public:virtual void show() {std::cout Base class std::endl;}
};class Derived : public Base {
public:void show() override {std::cout Derived class std::endl;}
};int main() {Base* basePtr;Derived derivedObj;basePtr derivedObj;basePtr-show(); // Calls Derived::show() through the virtual function tablereturn 0;
}在这个示例中Base 类和 Derived 类都有一个虚函数 show()。当通过 basePtr-show() 调用虚函数时实际上会根据对象 derivedObj 的实际类型在虚函数表中查找正确的虚函数地址然后调用 Derived::show()。这就是虚函数表的工作方式。
虚函数表的内部结构在不同的编译器和平台上可能会有所不同。我无法在这里直接为您提供一个完整的虚函数表的打印输出因为虚函数表的具体结构可能会受到编译器、类的层次结构以及继承关系等因素的影响。
但是我可以向您展示一个概念性的虚函数表结构帮助您理解它的大致原理。请注意这只是一个示意图实际虚函数表的结构可能会更加复杂。
假设我们有一个类 Base 和一个派生类 Derived它们都有一个虚函数 show()。
虚函数表示意图Base类虚函数表
---------------------
| 指向 Base::show() |
---------------------Derived类虚函数表继承自Base类
---------------------
| 指向 Derived::show()|
---------------------在这个示意图中每个类都有一个指向其虚函数的指针这个指针构成了虚函数表的一部分。当一个类没有虚函数时它的虚函数表可能为空。派生类会继承基类的虚函数表并在需要时进行覆盖。这样通过对象的虚函数指针可以在运行时查找到正确的虚函数实现。
请注意虚函数表的实际结构会受到编译器优化和内存布局等因素的影响因此它的具体形式可能会因编译器而异。
8.虚函数指针
虚函数指针的具体样子会受到编译器和平台的影响因此无法直接为您提供精确的打印输出。虚函数指针通常是一个指向虚函数表的指针用于在运行时查找和调用适当的虚函数。
以下是一个简化的示例来说明虚函数指针的概念
#include iostreamclass Base {
public:virtual void show() {std::cout Base class std::endl;}
};class Derived : public Base {
public:void show() override {std::cout Derived class std::endl;}
};int main() {Base* basePtr;Derived derivedObj;basePtr derivedObj;// 虚函数指针的示意这是一个虚函数表的指针void** vptr reinterpret_castvoid**(basePtr);// 第一个槽位通常是指向虚函数表本身的指针后面是实际的虚函数指针// 注意实际虚函数指针的内容可能因编译器和平台而异void* firstSlot *vptr;void* showFunctionPtr *(vptr 1);std::cout Address of virtual function table: firstSlot std::endl;std::cout Address of show() function: showFunctionPtr std::endl;return 0;
}请注意这个示例中展示的内容是概念性的实际虚函数指针的结构会更加复杂并且受到编译器和平台的影响。虚函数指针通常位于对象的内存布局的开头部分并指向类的虚函数表。在运行时通过虚函数指针查找虚函数表然后找到正确的虚函数地址进行调用。
9.抄自别的文章——C中虚函数的实现 C 中虚函数的实现涉及到虚函数表vtable和虚函数指针vptr这是实现多态性的关键。
虚函数表和虚函数指针允许程序在运行时确定要调用的函数而不是在编译时确定。
虚函数表vtable
对于每个拥有虚函数的类编译器会生成一个虚函数表通常在类的内部作为类的一部分。这个虚函数表是一个指向函数指针的数组其中包含了该类中每个虚函数的地址。虚函数表的第一个函数指针通常指向类的析构函数。接下来是按照虚函数在类中声明的顺序排列的函数指针。子类将继承父类的虚函数表并可以在其末尾添加自己的虚函数指针。
虚函数指针vptr
对于每个类的对象编译器会生成一个虚函数指针通常称为vptr该指针指向对象所属类的虚函数表。这个vptr通常位于对象的内存布局的开头。当调用虚函数时实际上是通过对象的vptr找到正确的虚函数表然后在虚函数表中查找要调用的函数的地址最后执行该函数。
多态的工作机制
当通过基类指针或引用调用虚函数时程序首先访问对象的vptr然后从虚函数表中找到要调用的函数。这个机制允许在运行时根据对象的实际类型而不是指针或引用的静态类型来调用正确的函数实现了多态性。
注意事项
构造函数不能是虚函数因为在对象的构造过程中虚函数表可能尚未完全设置。而析构函数可以为虚函数。C标准并未规定虚函数表和虚函数指针的实现方式因此不同编译器可能有不同的底层实现。但在大多数情况下它们遵循上述概念。