Chinaunix首页 | 论坛 | 博客
  • 博客访问: 87967
  • 博文数量: 38
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 535
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-03 15:11
文章分类

全部博文(38)

文章存档

2011年(1)

2010年(3)

2009年(19)

2008年(15)

我的朋友

分类:

2009-02-18 16:13:47

一. C++的多态
C++中的多态是靠虚函数来实现的。
//虚函数示例代码
class A{
public:
  virtual void fun(){cout<<1<
};
class B : public A{
public:
  void fun(){cout<<2<
};
 
void main(){
  A *a = new B;
  a->fun();
}
 
打印结果为2
如果class A中将关键字virtual去掉,则打印结果为1.
 
总结:只有在基类中将函数声明为虚函数,才能实现多态。
 
二. C++多态的实现原理
    虚函数如何根据对象的不同而调用不同的函数呢?
    如果一个类中有虚函数存在,则编译器会在类中插入一个指针,叫做vptr指针,该指针指向一个表,叫做vtbl。vtbl的作用是保存每一个虚函数的地址。看这段代码:
  A *a = new B;
  a->fun();
执行这段代码时,首先取出vptr的值,这个值是vtbl的地址。根据该值找到vtbl,在表vtbl中取得该虚函数fun()的地址,然后调用该函数。在这儿,表vtbl中fun()的地址为对象B中的地址。这样就实现了多态。
 
    而对于class A和class B来说,他们的vptr指针存放在何处呢?其实这个指针就放在他们各自的实例对象里。由于class A和class B都没有数据成员,所以他们的实例对象里就只有一个vptr指针。通过上面的分析,现在我们来实作一段代码,来描述这个带有虚函数的类的简单模型。
  #include
  using namespace std;
  //将上面“虚函数示例代码”添加在这里
  int main(){
  void (*fun)(A*);
  A *p=new B;
  long lVptrAddr;
  memcpy(&lVptrAddr,p,4);
  memcpy(&fun,reinterpret_cast(lVptrAddr),4);
  fun(p);
  delete p;
  system("pause");
  }
    输出的结果为3.现在开始一步一步分析。
    void (*fun)(A*) 定义了一个函数指针fun,该函数有一个参数,为指向A的指针。这个函数指针待会儿会被用来保存从vtbl中取出的函数地址。
    long lVptrAddr; 这个long变量用来保存vptr的值。
    memcpy(&lVptrAddr,p,4); 前面说了,p的实例对象中只有vptr指针,所以我们就放心大胆地将p指向的内存地址的前4bytes内容复制到lVptrAddr,复制出来的4bytes内容就是vptr指针,即vbtl的地址。/*指针为4bytes*/
    memcpy(&fun,reinterpret_cast(lVptrAddr),4);从vbtl中取出前4bytes内容,即存放在函数指针fun中。注意:由于lVptrAddr不是指针,要先将其转化为指针类型。
    fun(p) 调用了刚才取出的函数,也就是B中的fun()。注意:这儿多了一个参数p,其实类成员在函数调用的时候,默认都有一个this指针,这个p就是那个this指针,不写也可以,写成fun()也没问题。
 
三. Java中的多态
Class A{
  public void fun(){
    System.out.println("1");
  }
}
Class B extends A{
  public void fun(){
    System.out.println("2");
  }
}
public Class C{
  public static void main(String[] args){
    A a = new B();
    a.fun();
  }
}
这儿打印的是2.说明Java中默认函数就是虚函数。(虽然Java中没有虚函数的概念,可以这么认为^_^)
 
    但是,如果将fun()声明为私有函数的话,代码如下:
Class A{
  private void fun(){
    System.out.println("1");
  }
  public void doFun(){
    fun();
  }
}
Class B extends A{
  private void fun(){
    System.out.println("2");
  }
}
public Class C{
  public static void main(String[] args){
    A a = new B();
    a.doFun();
  }
}
 
打印结果为1.  而这样的代码在C++中打印结果照样还是多态的效果,即打印结果为2.不知道什么原因,Java的多态实现原理不清楚。
 
阅读(634) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~