做2手物品通过网站去卖掉好做吗,现在流行的网站开发语言,河南省建设工程招标投标信息网,做房产网站需要了解什么文章目录 前言虚函数是什么#xff1f;如何使用虚函数#xff1f; 纯虚函数是什么#xff1f;虚函数与普通函数的区别虚表虚表是什么#xff1f;含有虚表的类内存结构图如何找到虚表的地址#xff1f;示例代码代码解释 多态是什么#xff1f;如何使用多态#xff1f;为什… 文章目录 前言虚函数是什么如何使用虚函数 纯虚函数是什么虚函数与普通函数的区别虚表虚表是什么含有虚表的类内存结构图如何找到虚表的地址示例代码代码解释 多态是什么如何使用多态为什么要使用多态 多态遇到的所有情况 总结 前言
C 是一种功能强大的编程语言以其面向对象编程OOP特性而闻名。虚函数和多态是 C 面向对象编程中的两个重要概念它们使得代码更灵活、更具扩展性。本篇文章将介绍虚函数与多态包括其定义、使用方法及其在实际编程中的作用。 虚函数是什么
虚函数是一种在基类中使用 virtual 关键字声明的函数它允许在运行时通过基类指针或引用调用子类的重写版本。这种机制使得 C 能够实现多态性。
如何使用虚函数
在基类中声明虚函数并在子类中重写该虚函数。基类指针或引用可以指向子类对象并在运行时调用子类的重写版本。
#include iostreamclass Base {
public:virtual void show() {std::cout Base show std::endl;}
};class Derived : public Base {
public:void show() override {std::cout Derived show std::endl;}
};int main() {Base* ptr new Derived();ptr-show(); // 调用的是 Derived 的 show 方法delete ptr;return 0;
}纯虚函数是什么
纯虚函数是一种没有实现的虚函数必须在派生类中实现。它使用 0 语法来声明。声明纯虚函数的类称为抽象类不能直接实例化。
class AbstractBase {
public:virtual void pureVirtualFunction() 0; // 纯虚函数
};class ConcreteDerived : public AbstractBase {
public:void pureVirtualFunction() override {std::cout ConcreteDerived implementation of pureVirtualFunction std::endl;}
};int main() {// AbstractBase obj; // 错误不能实例化抽象类ConcreteDerived obj;obj.pureVirtualFunction(); // 调用派生类实现的纯虚函数return 0;
}虚函数与普通函数的区别 调用时机 普通函数在编译时确定调用的函数。虚函数在运行时确定调用的函数动态绑定。 多态性 普通函数不支持多态性。虚函数支持多态性可以通过基类指针或引用调用派生类的重写版本。
虚表
虚表是什么
在 C 中虚表vtable是一个由编译器维护的数据结构用于实现虚函数的动态绑定。当一个类中包含虚函数时编译器会为这个类创建一个虚表。虚表是一个指针数组其中每个指针指向该类的虚函数实现。当通过基类指针或引用调用虚函数时程序会通过虚表找到实际要调用的函数。
每个包含虚函数的类对象都有一个隐藏的指针称为虚表指针vptr它指向该对象所属类的虚表。因此通过虚表指针程序可以在运行时动态地确定调用哪个函数。
含有虚表的类内存结构图
有下面这样的两个类
class Base {
public:virtual void func1();int baseData;
};class Derived : public Base {
public:void func1() override;void func2();int derivedData;
};
它的内存结构图如下
-----------------
| Derived object |
-----------------
| vptr -----------------------------------
| derivedData | |
----------------- |
| baseData | |
----------------- ||||----------------- -----------------| Virtual Table | | Virtual Table || for Derived | | for Base |----------------- -----------------| func1() | | func1() || Derived::func1 | | Base::func1 |----------------- -----------------| func2() || Derived::func2 |-----------------
如何找到虚表的地址
找到虚表地址的方法涉及使用一些底层的 C 技巧和对内存布局的理解。以下是一个简单的示例代码用于展示如何找到一个类对象的虚表地址并打印虚表中的内容。
示例代码
#include iostreamclass Base {
public:virtual void func1() {std::cout Base::func1 std::endl;}virtual void func2() {std::cout Base::func2 std::endl;}
};class Derived : public Base {
public:void func1() override {std::cout Derived::func1 std::endl;}void func2() override {std::cout Derived::func2 std::endl;}
};typedef void(*FuncPtr)();void printVTable(FuncPtr* vtable) {std::cout Virtual Table Address: vtable std::endl;for (int i 0; vtable[i] ! nullptr; i) {std::cout Function i address: vtable[i] std::endl;}
}int main() {Derived obj;// 获取虚表指针的地址FuncPtr* vptr *reinterpret_castFuncPtr**(obj);printVTable(vptr);return 0;
}代码解释 类定义 Base 类中定义了两个虚函数 func1 和 func2。Derived 类继承自 Base 并重写了这两个虚函数。 函数指针类型 typedef void(*FuncPtr)(); 定义了一个函数指针类型 FuncPtr用于指向虚函数。 打印虚表函数 printVTable 函数接受一个虚表指针数组并打印虚表地址和其中每个函数的地址。 main 函数 创建一个 Derived 类对象 obj。使用 reinterpret_cast 将对象的地址转换为虚表指针数组的指针从而获取虚表地址。调用 printVTable 函数打印虚表内容。
多态是什么
多态性是面向对象编程的一种特性它允许通过基类指针或引用在运行时调用不同子类的重写方法。多态性使得代码更灵活和可扩展。
如何使用多态
通过基类指针或引用指向子类对象并调用基类中的虚函数。在运行时根据实际指向的对象类型调用相应的重写方法。
#include iostreamclass Animal {
public:virtual void sound() {std::cout Some generic animal sound std::endl;}
};class Dog : public Animal {
public:void sound() override {std::cout Bark std::endl;}
};class Cat : public Animal {
public:void sound() override {std::cout Meow std::endl;}
};void makeSound(Animal* animal) {animal-sound(); // 根据实际对象类型调用相应的 sound 方法
}int main() {Dog dog;Cat cat;makeSound(dog); // 输出 BarkmakeSound(cat); // 输出 Meowreturn 0;
}为什么要使用多态
代码复用多态性允许通过统一的接口调用不同子类的方法提高代码的复用性和可维护性。灵活性多态性使得程序在运行时根据实际情况调用不同的方法提高了代码的灵活性和扩展性。可扩展性可以在不修改已有代码的情况下添加新的子类并在运行时通过多态性使用它们。
多态遇到的所有情况 通过基类指针或引用调用子类方法 使用基类指针或引用指向子类对象调用虚函数实现多态性。 对象切片问题 如果将子类对象赋值给基类对象会发生对象切片问题子类的附加属性和方法会被切掉。 Base baseObj derivedObj; // 对象切片丢失 Derived 部分多重继承中的多态 C 支持多重继承可以通过虚继承解决多重继承中的菱形继承问题使多态性依然有效。 虚析构函数 在有多态的情况下基类通常需要一个虚析构函数以确保通过基类指针删除派生类对象时正确调用派生类的析构函数。 class Base {
public:virtual ~Base() {std::cout Base destructor std::endl;}
};class Derived : public Base {
public:~Derived() {std::cout Derived destructor std::endl;}
};int main() {Base* ptr new Derived();delete ptr; // 正确调用 Derived 的析构函数return 0;
}总结
虚函数和多态是 C 中面向对象编程的重要特性通过虚函数可以实现多态性使得代码更加灵活和可扩展。虚函数允许在运行时通过基类指针或引用调用子类的重写方法而纯虚函数则强制派生类实现某些方法使得抽象类无法实例化。多态性使得程序可以在运行时根据实际对象类型调用相应的方法提升了代码的复用性、灵活性和可扩展性。然而在使用多态时需要注意对象切片问题和虚析构函数的使用以确保正确的对象管理和方法调用。掌握虚函数和多态的概念和应用对于提高 C 编程水平和开发效率至关重要。