虚拟继承、虚函数学习总结
一、虚函数。
其实是比较简单的,它的存在就是为了给子类继承,并且提供多个接口,所谓多个接口,就是多态性,它的主要特点就是父类的指针可以指向子类的对象,这样的话,在继承上会有好处。例如,某个父类有多个子类,在不知道会调用哪一个子类对象的情况下,可以定义一个父类的指针
f
,这样就实现了所谓的“接口”功能,在知道了要使用哪一个子类的时候,就直接把父类的指针
f
指向那个子类的对象,以后的操作都是采用父类的指针
f
,这样显然就有优点了,可以把对子类的操作封装起来,跟它使用哪一个子类没有关系了,因为在被封装起来的操作里面操作的对象是父类的指针
f
,然后这些被封装的操作就提供了一个“接口”,要用哪一个类的对象,就把那一个类对象的地址给父类的指针
f
。
二、虚函数非虚拟继承
CSDN
的博客上有一篇文章《
C++
虚函数表解析》,作者:陈皓
网址:
http://blog.csdn.net/haoel/archive/2007/12/18/1948051.aspx
说的是虚函数在内存中的格局,讲得很好理解。通过
vs2005
调试查看内存也是一样的。就是虚函数表。
三、虚拟继承。
CSDN
的博客上有一篇文章《
C++
对象内存布局》,作者:陈皓
网址
http://blog.csdn.net/haoel/archive/2008/10/15/3081328.aspx
里面讲述了
c++
虚函数的各种继承的内存布局,讲得非常详细,大部分的内容都很容易看懂,但是在
讲解虚拟继承上还有一点不足,就是虚函数的虚拟继承漏了一点内容,虚基函数表(vbtbl)
的相关内容。
另一篇文章写得很好,也是CSDN
博客上的,《
c++
虚继承对象的内存布局
》
网址:
http://blog.csdn.net/BlueDog/archive/2009/10/22/4711169.aspx
在《
C++
对象内存布局》有一个名词叫做“钻石型虚拟多重继承”,之前不知道该怎么称呼这种继承,画成图,它们的形状就像棱形,一个基类产生两个子类,两个子类又同时被另一个“孙类”虚拟继承,最简单的虚拟继承就是这样子。
1、
没有涉及虚函数的虚拟继承。如果不管内部如何实现,简单的说就是“孙类”只拷贝一次基类,如果涉及到内存布局,那就必须通过
debug
,查看执行时的内存,
《
c++
虚继承对象的内存布局
》说到了这一点。通过内存查看“孙类”对象的地址,这个地址就相当于有虚函数的虚拟继承的“
Virtual Base Class Table
”简称“
VBTBL
”,当然名称可能有点问题,因为它只是包含用来寻找虚基类表的偏移值,而不是虚基类表的指针。在没有虚函数的情况下,它保存的内容同样有两项(因为只有一个基类),第一项为
0
,因为没有虚函数,第二项为本地址相对于基类的偏移值。从“孙类”的内存中发现,基类的内容放在在最后面,这也跟有虚函数的时候一样。可能是为了跟有虚函数的时候统一,格式是一样的,这样的话,在没有虚函数的时候,有些是没有用的,如
B
子类也有个类似于“
VBTBL
”的东西,如果没有理解错的话,它应该是没用的,访问基类的时候用不着它。在查看内存的时候还发现了一些现象,内存里面没有函数的地址,只有变量空间,这个大概就是非虚函数跟虚函数的不同吧。通过查看内存可以很好的理解底层的东西。
2、
含有虚函数的虚拟继承。这就涉及到了虚函数表、虚基类、
VBTBL
。
《
c++
虚继承对象的内存布局
》里面说得很详细,那个“孙”类对象的内存结构图看起来非常的明确,我在
vs2005
里面查看,完全一样。
3、
总结:有虚拟继承的“孙”类的对象的内存格局是这样的,被虚拟继承的基类放在最后,子类按顺序放在基类的前面。子类的对象的内存格局,基类也是放在最后。虚拟继承的每一个类都有“
VBTBL
”之类的东西。
分享到:
相关推荐
要求:1、虚函数 多态 多态表现为 基类 基类指针和继承间的关系 2、带有多对象成员。定义 3、体现继承 虚拟继承(要通过至少三层 父类父类子类) 虚函数 (3层 纵向关系) 水平方向上:体现出继承顺序 先虚拟继承 ...
综上所述,该实验通过设计抽象类和派生类,使用虚函数实现多态性,展示了面向对象编程的关键概念,如继承、封装、多态和动态绑定。这些概念对于理解和编写复杂的C++程序至关重要。通过这样的实践,学生能够更好地...
可见性继承比较简单,而虚拟继承对学习c++的难度较大。 首先,虚拟继承与普通继承的区别有: 假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误; ...
2. **多态性实现**:当一个类继承自包含虚函数的基类时,子类可以重新定义(重写)该虚函数,这样就实现了运行时的多态性。 3. **虚函数表**:为了支持虚函数的动态绑定,C++编译器会在每个含有虚函数的对象中添加一...
- 这是因为构造函数调用的顺序是从基类到派生类,而在构造函数中调用虚函数时,虚拟表(VTable)中的指针还未被更新为最终派生类的版本,导致调用的总是当前类的函数。 4. **潜在的安全问题** - 如果允许在构造函数...
2. **内存布局变化**:虚拟继承会改变对象的内存布局,增加了一个指向虚基类的指针(虚表指针,vptr),用于在运行时确定对象的实际类型。 3. **性能影响**:虽然虚拟继承解决了菱形问题,但它的内存开销和构造/析...
### 多态的实现及虚函数详解 #### 引言:多态的演变与意义 在计算机科学领域,随着技术的演进,程序设计语言经历了从低级到高级的跨越,其中面向对象编程语言(如C++、Java、C#等)的兴起,标志着软件设计思想的一...
如果类中有虚函数,应考虑使析构函数也虚拟,以确保在删除基类指针指向的派生类对象时能正确调用派生类的析构函数。 ```cpp class Base { public: virtual ~Base() {} // 虚析构函数声明 }; class Derived : ...
为了更好地理解虚函数的性能影响以及如何通过静态分析对其进行优化,本文将探讨虚拟函数分析的具体方法和构建技术。 首先,需要明确虚函数的概念。在C++中,虚函数是一种特殊的成员函数,在基类中被声明为virtual,...
编译器实现虚函数调用通常采用VTABLE(虚拟表)机制。对于每个包含虚函数的类,编译器都会创建一个VTABLE,其中包含了该类所有虚函数的地址。当创建类的实例时,每个实例都会包含一个额外的指针`vptr`,指向其所属类...
在C++中,虚函数的作用就是确保在继承层次结构中,能够正确地调用到对象实际所属类的成员函数,而不是仅仅局限于基类的版本。 首先,虚函数的声明使用`virtual`关键字。例如: ```cpp class A { public: virtual ...
在这个例子中,`Base` 类包含了一个虚函数 `foo()`,而 `Derived` 类继承自 `Base` 并重写了 `foo()` 函数。在 `main` 函数中,首先创建了 `Base` 类的一个对象,并通过基类指针 `pb` 调用了 `foo()` 函数。然后,...
虚函数的目的是为了提供一个可以被继承和重写的方法,以便在不同的派生类中实现不同的功能。 例如,我们可以声明一个虚函数myint(),如下所示: ```csharp public class MyClass { public virtual int MyInt() { ...
### C++ 中的继承、多态、虚函数与纯虚函数 #### 继承 **概念解析** 在面向对象编程语言如 C++ 中,继承是一种让一个类(派生类)能够继承另一个类(基类)特性的机制。这种机制不仅能够重用代码,还能在原有基础...
在实际编程中,虚拟多重继承可以增加代码的灵活性,但也会带来额外的开销,包括内存消耗(由于虚基类表的存在)和运行时性能影响(由于虚函数调用和虚基类的处理)。因此,虽然C++支持虚拟多重继承,但在设计类层次...
总结来说,C++的虚函数表是实现多态性的一种机制,它存储了类中所有虚函数的地址,确保通过父类指针调用时能够正确执行子类的函数。理解虚函数表的工作原理有助于深入掌握C++的面向对象编程和多态特性。
虚函数调用通常涉及到虚拟表(vtable)和虚拟指针(vptr),这增加了每次函数调用的开销。在某些性能敏感的应用场景下,这种开销可能会成为瓶颈。例如,在图书馆媒介管理系统中,如果系统频繁地处理大量媒体的借阅和...
子类继承父类时,子类的虚函数表会继承父类的虚函数表,从而实现多态。 指针是 C++ 编程中的一种基本数据类型,用于存储内存地址。指针可以指向变量、函数或数组。指针的使用可以实现动态内存分配、函数指针、数组...
在Java中,每个非`static`、非`final`的方法都是虚拟的,也就是说,默认情况下,方法调用是基于对象实例的实际类型进行动态绑定的,无需显式声明为虚函数。如果希望一个方法不被子类覆盖,可以使用`final`关键字进行...