C++中的虚函数

C++中的虚函数

引言

C++中的虚函数,是实现C++多态的一个重要手段。这里会介绍一下虚函数和RTTI。


一、虚函数表和虚函数表的指针

要了解C++是如何实现虚函数这功能,首先我们就要了解一个重要概念:虚函数表(Virtual Tables,之后简称vtbls)。

虚函数表是类额外的一个静态数组。其中存放该类的虚函数信息等。

在编译的时候,编译器同时也会为基类创建一个成员变量:用于存放类对象的虚拟表的位置(virtual Table Pointers,之后简称vptrs)。

下面举一个例子来解释虚函数表。

class CBase
{
public:
    virtual void f1();
    virtual void f2(int i);
    void f3(const char * p);
};
class CSub1 : publicCBase
{
public:
    virtual void f1();
};
class CSub2 : publicCBase
{
public:
    virtual void f2(int i);
};
 
int _tmain(int argc,_TCHAR* argv[])
{
    CBase * p1 = newCSub1();
    p1->f1();
    p1->f2(1);
    delete p1;
 
    CBase * p2 = newCSub2();
    p2->f1();
    p2->f2(1);
    delete p2;
 
    return 0;
}
下图便是其中虚函数表的具体情况
图1.1

在程序中,new CSub1(),系统为这个new出来的对象的创建一个数组,存放了CSub1对象的虚函数信息,并且将这个数组的地址赋值给该对象的vptrs

接下来将CSub1对象的地址付给了指针p1。而这个指针的类型是CBase*,但是它所指向的对象却是CSub1

当执行语句p1->f1()的时候,利用指针找到内存中的CSub1对象,随后再通过该对象的vptrs找到CSub1对象的虚函数表,在表中找到了虚函数f1实现的地址,找到真正的f1函数。可以看图1.1,CSub1的f1所指向的是CSub1自己的类成员函数f1。

当执行语句p1->f2(1)的时候,和上面的步骤一样,最终找到了CBasef2

同样p2指针也类似,这里就不做累述。


二、RTTI

Run-Time Type Information,在程序运行时,能够判断一个对象的类型。承接上一节提到的静态类型和动态类型。

void deal(CBase * p);
……
deal(new CSub1());

这里作为函数deal的参数p的静态类型是CBase*,这是在编译器进行编译的时候,能够判断的类型。但是,如果我们将CBase的子类CSub1的对象的指针作为参数给p赋值后,p的动态类型便是CSub1。所谓动态类型便是在程序运行的时候,对象实际的类型。这就是RTTI要做得事。

 

对于RTTI,其中介绍两个个操作。

(1)dynamic_cast,用于多态类型的转换。经常被用来将基类对象的指针转换成子类对象的指针。

比如:

CBase * p = newCSub1();
CSub1 * ps1 = p;//1
CSub1 * ps1 =dynamic_cast<CSub1 *>(p); //2

上面第一种转换,编译器是无法通过的,但是第二种转换编译是没有问题的。

 

(2)typeid,用于确定对象的精确类型。记住这里是对象的类型,传入一个指针,它只会去判断这个指针的类型,而不是这个指针指向对象的类型。

CBase * p1 = newCSub1();
CBase * p2 = newCSub2();
CBase * p = newCBase();
cout<<"typeid(p).name():"<<typeid(p).name()<<endl;
cout<<"typeid(p1).name():"<<typeid(p1).name()<<endl;
cout<<"typeid(p2).name():"<<typeid(p2).name()<<endl;
cout<<"typeid(*p).name():"<<typeid(*p).name()<<endl;
cout<<"typeid(*p1).name():"<<typeid(*p1).name()<<endl;
cout<<"typeid(*p2).name():"<<typeid(*p2).name()<<endl;
delete p1;
delete p2;
delete p;

这里的输出便是:


其实typeid这个操作返回的类型是type_info(这里就不再做介绍了)。


三、总结

在C++中利用虚函数,可以实现很多面向对象的模式。可以在设计模式(Design Pattern)中的各处找到虚函数的影子,所以要怎么用好虚函数,可以去参考设计模式。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章