C的对象模型基于编译时和运行时机制的组合,以支持继承,多态性和封装等特征。从本质上讲,它依靠班级的概念作为创建对象的蓝图。每个对象都是类的实例,其中同时包含数据(成员变量)和代码(成员函数)。
继承:继承允许基于现有的(基础类)创建新类(派生类)。派生的类继承其基类的成员(数据和功能),可以添加自己的成员或覆盖现有成员。这促进了代码重用并建立“ IS-A”关系。例如, Dog
课可能会从Animal
阶级继承。
虚拟函数:虚拟函数是基类中使用virtual
关键字声明的成员函数。它们启用运行时多态性,这意味着要调用的正确函数是根据对象的实际类型在运行时确定的,而不是其声明的类型。这对于实现灵活性和可扩展性至关重要。它背后的机制是虚拟函数表(VTable) 。每个具有虚拟函数的类都有其自己的VTable,这是该类中实现的虚拟函数的指针表。包含虚拟函数的类的每个对象都有一个隐藏的指针(通常称为VPTR),指向其类的VTable。当调用虚拟函数时,运行时使用VPTR在VTable中找到正确的函数。
例子:
<code class="c ">class Animal { public: virtual void makeSound() { std::cout makeSound(); // Calls Dog::makeSound() due to virtual function delete animal; return 0; }</code>
在此示例中, makeSound
是虚拟函数。即使将animal
宣布为Animal
指针,但由于可VT的机制,在运行时(从Dog
类类中)的正确makeSound
功能也被调用。
与非虚拟函数相比,使用虚拟函数引入了性能开销。这个高架源于几个因素:
但是,这些开销通常很小,通常可以忽略不计,尤其是与虚拟功能提供的多态性和代码可维护性的好处相比。现代编译器采用各种优化技术来最大程度地降低虚拟功能的性能影响,例如内部和功能指针缓存。只有在代码的性能 - 关键性段中调用虚拟函数时,性能影响才有意义,即使这样,除非函数被称为大量次数,否则差异通常是边缘的。
C继承以多种方式影响内存管理和对象大小:
unique_ptr
, shared_ptr
)可以简化内存管理。静态调度和动态调度是确定在运行时要调用哪种功能的两种不同的方法。关键区别在于做出决定时:
说明区别的示例:
<code class="c ">class Animal { public: void makeSound() { std::cout makeSound(); // Static dispatch: Calls Animal::makeSound() animal->move(); // Dynamic dispatch: Calls Dog::move() delete animal; return 0; }</code>
在此示例中, makeSound
使用静态调度,因为它不是虚拟的,而move
使用动态调度,因为它是虚拟的。这表明了virtual
关键字的存在(或不存在)如何决定调度机制。
以上是C的对象模型如何工作,包括虚拟函数和继承?的详细内容。更多信息请关注PHP中文网其他相关文章!