继承之虚函数+空类大小

来源:互联网 发布:java反复执行一个任务 编辑:程序博客网 时间:2024/04/30 22:06
虚函数的思想是从Simula借来的,并经过一定修改获得的。引入虚函数是为了增加程序设计的灵活性。

一个基类的虚函数在不同的派生类里面可以有不同的实现。

在关于对象布局方面。C++把一个类中所有的虚函数定义成一个指向函数的指针数组。可以通过调用这个指针数组中的函数指针来指向需要调用的虚函数(有点绕口了~)。简单的说,就是通过调用函数指针来调用虚函数,而这个函数指针被存储在一个指针数组中。这个指针数组就是通常所说的虚函数表或vtbl。每个有虚函数的类的对象都会有一个隐式的指针,叫做vptr,指向这个对象的类的虚函数表(vtbl)。

空类的大小为什么为1?
首先,我们要清楚实例化是什么意思。所谓的实例化就是在内存中分配一块地址,而每个实例都会有一块独一无二的地址。按照语法,我们可以知道,空类也是可以被实例化的,那么问题来了,如果空类的大小为0,要怎么为空类分配一块独一无二的地址呢?所以,为了达到这个目的,编译器往往会向空类里面隐含的加一个字节,这样就可以在内存中获得一块第一无二的地址啦。所以空类的大小就变成1啦。

编译器在处理类的大小时,因为大多数CPU对字长的整数倍操作起来会更快,所以,编译器会做出一些优化,在类成员之间或者最后插入一段内存,让空类的大小达到字长的整数倍,这个叫做“补齐”(padding)。所以,C++标准紧紧规定成员的排列按照类定义的顺序,但是不要求在存储器中是紧密排列的。

在C++中基类希望派生类进行覆盖的函数通常会定义为虚函数。当我们使用指针或者引用调用函数的时候,这个调用将会被动态绑定。根据引用和指针绑定的对象类型的不同,虚函数会执行不同的版本。如果指针或者引用绑定的是基类,那么执行的就是基类的虚函数,如果是派生类那么就是派生的虚函数。(每个基类通常都应该定义一个虚析构函数,即使这个虚析构函数什么都不做。)成员函数如果没有被声明为虚函数,其解析过程发生在编译时而不是运行时。
但是派生类也可以不重写继承自基类的虚函数。如果派生类没有重写基类中的某个函数,那么派生类就会直接继承这个函数在基类中的版本。
例如:
#include <iostream>class A{public : virtual void f(){ std::cout << "this is A" << std::endl; } virtual void g(){ std::cout << "this is A's g" << std::endl; }};class B : public A{public : virtual void g(){ std::cout << "this is B's g" << std::endl; }};int main(){ B b; b.f(); b.g(); system("PAUSE"); return 0;}


0 0
原创粉丝点击