c++ 之多态篇(下)----虚表,多态调用

本文详细探讨了C++中的多态特性,包括纯虚函数的作用,如何实现动态多态调用,以及深入解析虚表的工作原理。通过对这些概念的理解,读者能够更好地掌握C++的多态机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

纯虚函数

定义:在成员函数的形参列表后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数              在派生类中重新定义以后,派生类才能实例化出对象。 

 测试代码:
class Base//抽象类
{
public:
	virtual void FunTest()=0;//纯虚函数
};
class Dervied:public Base
{
public:
    virtual void FunTest()
	{
		cout<<"Dervied::FunTest()"<<endl;
	}
};
int main()
{
	//B b;//会报错
	Dervied d;
	d.FunTest();
      return 0;
}

动态多态调用

 测试代码:
   
class Base
{
public:
  virtual void Fun()
  {
	  cout<<"Base::Fun()"<<endl;
  }
};
class Derived
{
public:
  virtual void Fun()
  {
	  cout<<"Derived::Fun()"<<endl;
  }
};

void FunTest()
{
 Base *pb=new Base;
 pb->Fun();
 pb=(Base*)new Derived;
 pb->Fun();
}
int main()
{
 FunTest();
}

分析如下:
                       
         

虚表剖析

对于有虚函数的类,编译器都会维护一张虚表,对象的前四个字节就是指向虚表的指针

测试代码:
class CTest 
{
public:      
	CTest()
	{
		iTest = 10;
	}    
	virtual void Fun()
	{}
	
private:       
	int iTest;
};
int main() 
{       
	CTest t;
	t.Fun();
	cout<<sizeof(t)<<endl;     
	return 0; 
}

运行结果为:
                  

具体分析:
    

所以,Base类对象的对象模型如下:
                                                       
看一下下面两个例子。
(1)派生类继承基类,没有重写基类的虚函数。

测试代码:
class Base 
{ 
public:          
	Base()
	{
		m_iTest = 10;
	}           
	virtual void FunTest0()
	{
		cout<<"Base::FunTest0()";
	}           
	virtual void FunTest1()
	{
		cout<<"Base::FunTest1()";
	}           
	virtual void FunTest2()
	{
		cout<<"Base::FunTest2()";
	} 
  private:           
	  int m_iTest; 
};
class Derived:public Base 
{
public:          
	virtual void FunTest4()
	{
		cout<<"Derived::FunTest4()";
	}           
	virtual void FunTest5()
	{
		cout<<"Derived::FunTest5()";
	}           
	virtual void FunTest6()
	{
		cout<<"Derived::FunTest6()";
	} 
};
typedef void (*FUN_TEST)();
void FunTest() 
{          
	Base base;          
	cout<< "Base vfptr:"<<endl;          
	for (int iIdx = 0; iIdx < 3; ++iIdx)         
	{                   
		FUN_TEST funTest = (FUN_TEST)(*((int*)*(int *)&base + iIdx));
                   funTest();                   
				   cout<< ": "<<(int *)funTest<<endl;         
	}
          cout<<endl;
          Derived derived;         
		  cout<< "Derived vfptr:"<<endl;           
		  for (int iIdx = 0; iIdx < 6; ++iIdx)         
		  {                  
			  FUN_TEST funTest = (FUN_TEST)(*((int*)*(int *)&derived + iIdx));                  
			  funTest();                   
			  cout<< ": "<<(int *)funTest<<endl;         
		  } 
}
int main()
{
 FunTest();
 return 0;
}
具体分析如下:
            Base类的对象:
                       

     Derived类的对象:
                             
(2)派生类继承基类,并重写基类的虚函数。

测试代码:
 
class CBase 
{ 
   public:           
	   virtual void FunTest0()
	   {
		   cout<<"CBase::FunTest0()";
	   }           
	   virtual void FunTest1()
	   {
		   cout<<"CBase::FunTest1()";
	   }           
	   virtual void FunTest2()
	   {
		   cout<<"CBase::FunTest2()";
	   }           
	   virtual void FunTest3()
	   {
		   cout<<"CBase::FunTest3()";
	   }
};
class CDerived:public CBase 
{
public:           
	virtual void FunTest0()
	{
		cout<<"CDerived::FunTest0()" ;
	}           
	virtual void FunTest1()
	{
		cout<<"CDerived::FunTest1()" ;
	}           
	virtual void FunTest4()
	{
		cout<<"CDerived::FunTest4()" ;
	}           
	virtual void FunTest5()
	{
		cout<<"CDerived::FunTest5()" ;
	} 
};
typedef void (*_pFunTest)();
void FunTest() 
{         
	CBase base;           
	for (int iIdx = 0; iIdx < 4; ++iIdx)        
	{                   
		_pFunTest  pFunTest = (_pFunTest)(*(( int*)*(int *)&base + iIdx));                   
		pFunTest();
		cout<< ": "<<(int *)pFunTest<<endl;
    }
     cout<<endl;         
	 CDerived derived;          
	 for (int iIdx = 0; iIdx < 6; ++iIdx)         
	 {                  
		 _pFunTest  pFunTest = (_pFunTest)(*((int*)*(int *)&derived + iIdx));                
		 pFunTest();    
		 cout<< ": "<<(int *)pFunTest<<endl;
	 } 
}
int main() 
{         
	FunTest();            
	return 0;
}
结果分析:
                 CBase类对象:
                                         
      CDerived类对象:
                              
                               
      对象模型如下:
     
                               

  总结:

   1. 动态多态的条件:
                                  (1)基类中有虚函数,派生类中一定要重写基类的虚函数
                                          (2)必须使用基类的指针或引用调用派生类的虚函数。 
   2.基类虚表中的虚函数顺序是按照虚函数在类中的声明顺序。
   
   3.派生类虚表的形成过程(虚表存的是虚函数地址,以下为了说明方便,没有说存的是虚函数地址):
                                              (1)先拷贝基类的虚函数
                                                         (2)派生类若重写了哪个虚函数,就替换对应的基类虚函数
                                                         (3)最后跟上派生类自己的虚函数。
   4.多态调用过程:(虚函数)
                              (1)取虚表指针(对象的前4字节)
                              (2)取虚函数于虚表的偏移量
                              (3)调用虚函数

 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值