virtual 面向对象,他的多态性是如何体现的呢 那就要看我们的虚函数了, 我们的虚函数是我们在基类里面声明了一些能够在各个派生类里面重新定义的函数。编译器和装载程序能够保证对象和应用于他们的函数之间的正确的对应关系。
C++中,虚函数起了很大的作用,类中至少有一个虚函数的时候,类就会构造出一个虚函数表来指示这些函数的地址,假如继承该类的子类定义并实现了一个同名并具有同样函数签名(function siguature) 的方法重写了基类中的方法,那么虚函数表会将该函数指向新的地址。来看看此时的多态性:
当我们将基类的指针或引用指向子类的对象的时候,调用方法时,就会顺着虚函数表找到对应子类的方法而非基类的方法。
如果要用继承,那么一定要让析构函数是虚函数;如果一个函数是虚函数,那么在子类中也要是虚函数。
在我们的类中,如果有虚函数,那么我们的类里面就会多一个变量,那就是vptr,他是一个大小为四个字节的指针,指向我们的虚函数表!虚函数表中记录了类中的各个虚函数的入口地址,如果你重载了继承的虚函数,那么就存放自己的虚函数地址。否则就是父类的虚函数地址。
也可以来这样看,类的对象为了去找table,所以被加入了一个由编译器内部产生的指针,指向这个表格。
而为了找到函数的地址,每一个虚函数被指派一个表格的索引。
OK,下面我们来看一下Inside The C++ Object Model的例子:
class Point{
public:
virtual ~Point();
virtual Point& mult(float) = 0;
...
float x() const{ return _x;}
virtual float y() const{ return 0;}
virtual float z() const{ return 0;}
...
private:
Point(float x = 0.0};
float _x;
};
class Point2d : public Point{
public:
Point2d(float x = 0.0, float y = 0.0):Point(x), _y(y){}
~Point2d();
...
Point2d& mult( float );
float y() const{ return _y;}
...
protected:
float _y;
};
class Point3d : public Point2d{
public:
Point3d(float x = 0.0, float y = 0.0, float z = 0.0):Point2d(x, y), _z(z){}
~Point3d();
...
Point3d& mult( float );
float z() const{ return _z;}
....
protected:
float _z;
};
ok,看下面的声明:
Point *ptr;
我们要去用ptr去寻址一个Point2d或者Point3d的对象:
ptr = new Point2d;
ptr = new Point3d;
在这里,ptr的多态机制就有用了,他的主要的工作就是一个传送的机制。
OK,下面我们来看看上述代码的内存布局:
Point *p;
..
p->mult(p); 编译器转化为: (*p->_vptr_Point[2])(p);
在我们的【C/C++学习】之五、dynamic_cast这篇博客里面也涉及了一些多态的知识!
下面我们来看一下纯虚函数:
纯虚函数是在函数的形参表后面写上=0! 把函数定义为纯虚函数就是说,该函数为后代类型提供了可以覆盖的接口!但是这个类中的版本是绝不会调用的!
纯虚函数或纯虚方法是一个需要被非抽象衍生类执行的虚函数. 包含纯虚方法的类被称作抽象类;
要注意的是抽象类是不能实例化的!
而这个抽象类的子列只有把纯虚函数都给出实现才可以被实例化!
权限:
一个private权限的虚函数可以被子类重载,但是子类不能访问父类的虚函数,但是父类可以通过运行时多态的方式来调用子类重载后的虚函数。
一个protected权限的虚函数可以被子类重载,子类也可以访问父类的虚函数
一个public权限的虚函数可以被重载,子类也可以访问
2012/8/19
jofranks 于南昌