C++中的虚函数的作用主要是实现了多态的机制。关于多态,就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。也就是试图使用不变的代码来实现可变的算法。虚函数的实现包括两部分,虚函数指针和虚函数表。
虚函数指针虚函数指针 (virtual function pointer) 从本质上来说是一个指向函数的指针,与普通的指针并无区别。它指向用户所定义的虚函数,具体是在子类里的实现,当子类调用虚函数的时候,实际上是通过调用该虚函数指针从而找到接口。
虚函数指针是确实存在的数据类型,在一个被实例化的对象中,它总是被存放在该对象的地址首位,这种做法的目的是为了保证运行的快速性。与对象的成员不同,虚函数指针对外部是完全不可见的,除非通过直接访问地址的做法或者在DEBUG模式中,否则它是不可见的也不能被外界调用。
只有拥有虚函数的类才会拥有虚函数指针,每一个虚函数也都会对应一个虚函数指针。所以拥有虚函数的类的所有对象都会因为虚函数产生额外的开销,并且也会在一定程度上降低程序速度。
虚函数表的指针,实质是指针的指针。虚函数表的内容其实就是一个指针数组。
虚函数表虚函数表的指针存储在对象实例中最前面的位置。也就是说可以利用对象的实例地址得到虚函数表的地址,之后遍历虚函数表中的各个函数的指针,就可以调用与之对应的函数。
例子一#includeusing namespace std; class base {//基类中的虚函数 public: virtual void f() { cout << "base::f" << endl; } virtual void g() { cout << "base::g" << endl; } virtual void h() { cout << "base::h" << endl; } }; int main() { typedef void(*Fun)(void);//函数指针 base b; Fun pFun = NULL; base* p = &b; cout << "该对象的地址:" << p << endl; cout << "虚函数表的指针" << (int*)(&b) << "开始存的" << endl << endl; cout << "虚函数表的指针指向的地址10进制:" << *(int*)(&b) << "即虚函数表的指针存的内容" << endl; cout << "即虚函数表的地址:" << (int*)*(int*)(&b) << endl << endl; pFun = (Fun) * (int*)*(int*)(&b);//第一个虚函数的指针 cout << "第一个虚函数的地址:" << pFun << endl; pFun(); Fun gFun = NULL; gFun = (Fun) * ((int*)*(int*)(&b) + 1);//第二个虚函数的指针 Fun hFun = NULL; hFun = (Fun) * ((int*)*(int*)(&b) + 2);//第三个虚函数的指针 return 0; }
解释以下含义:
1、&b :对象b的地址
2、(int*)(&b): “虚函数指针vptr的地址”
3、*(int*)(&b):是虚函数表的地址;
4、 (int*)*(int*)(&b):虚函数表的地址转为int类型;
5、(Fun)*(int*)*(int*)(&b)虚函数表的int类型的地址再转为FUN函数指针类型
看一下 图
那么gFun = (Fun)((int)(int)(&b) + 1);了。首先(int*)(int)(&b)将虚函数表的指针转换为指向指针数组首元素的指针(即转换过程中,指针指向地址没变的),然后((int*)(int)(&b) + 1)这里就是数组的指针的正常 *** 作,现在这个指针指向了数组的第二个元素(即第二个虚函数指针),最后就是解引用,然后转换为Fun函数指针。
#includeusing namespace std; class base1 { public: virtual void f() { cout << "base1::f" << endl; } virtual void g() { cout << "base1::g" << endl; } virtual void h() { cout << "base1::h" << endl; } }; class base2 { public: virtual void f() { cout << "base2::f" << endl; } virtual void g() { cout << "base2::g" << endl; } virtual void h() { cout << "base2::h" << endl; } }; class base3 { public: virtual void f() { cout << "base3::f" << endl; } virtual void g() { cout << "base3::g" << endl; } virtual void h() { cout << "base3::h" << endl; } }; class Derive : public base1, public base2, public base3 { public: virtual void f() { cout << "Derive::f" << endl; } virtual void g1() { cout << "Derive::g" << endl; } virtual void h1() { cout << "Derive::h" << endl; } }; typedef void(*Fun)(void); void printVfun(int n, int * vTable) { for (int i = 0; i < n; ++i) { printf("function : %d :0X%x->", i, vTable[i]); Fun f = (Fun)(vTable[i]); f(); //访问虚函数 } cout << "" << endl; } int main() { Derive d; // (int*)(&b)这个是虚函数表指针vptr的地址 // *(int*)(&b)这个是虚函数表的地址 // 一个对象中有多个虚函数表时需要在 第二个虚函数表指针vptr:(int*)(&b)+1 int *vTable1 = (int *)*(int *)(&d);//第一个虚函数表的指针 printVfun(5, vTable1); int *vTable2 = (int *)*((int *)(&d) + 1);//第二个虚函数表的指针 printVfun(3, vTable2); int *vTable3 = (int *)*((int *)(&d) + 2);//第三个虚函数表的指针 printVfun(3, vTable3); }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)