标签:结合 存储 virt style cout 抽象类 抽象 子类 类型
1.非virtual函数,调用规则取决于对象的显式类型。例如
A* a = new B();
a->display();
调用的就是A类中定义的display()。和对象本体是B无关系。
2.virtual函数,具体调用哪个版本,取决于虚函数表。例如
A* a = new B();
a->v_display();
这个时候,对象a就需要查找自身的虚函数表,表中的v_display()是一个函数指针,可能指向不同类中的对应的v_display函数并调用对应版本的v_display。一般而言,如果B重写了v_display(),那么会调用B的v_display(),如果没有会调用A的display();
3.纯虚函数。结合2分析,纯虚函数在父类是没有定义的,如果子类继承后仍然不重写并定义对应的纯虚函数,那么子类也是抽象类,无法初始化对象,直到有一个类定义了这个虚函数。
这个类才可以初始化对象。并在这个对象上维护这个函数的虚函数表相关数据。
关于虚函数表:
一般存储在一个对象的固定的地址,我们甚至可以通过虚函数表来直接调用某些虚函数。
例如:
A* a = new B();
a就是对象a的地址
将a的地址强制转化成int型指针 (int*)a ,也就是理想化将对象看成int型数组,(因为对象的所有数据是按照类似数组规则的相邻地址块存储的,所以将a转化成int*就好比将一个对象转化成了一组int,每个int其实都是一个地址。)
而上述这些地址中每个地址存储的东西是什么呢?别的不知道,第一个存储的就是虚函数表,里边又是一组地址!我们将第一个地址解引用:
*(int*)(a)
然后得到了一个存储虚函数表指针的首地址,然后再将其强转成int*,这样虚函数表的第一个地址我们也得到了,那就是
(int*)*(int*)(a)
这个地址可以像int[] 一样计算 ,如果+1 就可以获得虚函数表的下一个函数。但是毕竟得到的都是每个函数的地址,所以我们还需要将它解引用:
*(int*)*(int*)(a) 这样就获得真实的函数指针了!到这里就简单了,假如我们调用的函数是void(void)类型的,我们创建一个函数指针类型:
typedef void(*Fun)(void)
这样如果上边从虚函数表中获得的函数指针也是void(void)类型的,我们就可以将其强转为对应的函数指针类型
即
Fun vfun = (Fun)*(int*)*(int*)(a);
vfun();
哦卖萧的。。。。。。
我这里有一组测试代码:
#include <iostream> #include <string> using namespace std; typedef void(*Fun)(void); class A { private : string s; public : virtual void display(); virtual void v_display(); virtual void v_0_display() const = 0; }; class B : public A { public: void display(); //void v_display(); void v_0_display () const; }; void A::display() { cout << "A::display" << endl; } void A::v_display() { cout << "A::v_display" << endl; } void B::display() { cout << "B::display" << endl; } //void B::v_display() //{ // cout << "B::v_display" << endl; //} void B::v_0_display() const { cout << "B::v_0_display" << endl; } int main(int argc, char* argv[]) { A* a = new B(); B* b = new B(); Fun vfun = NULL; vfun = (Fun)*((int*)*((int*)(a))+0); cout << "the address the first virtual function is" << (int*)*((int*)(a) + 0) << endl; cout << "------------virtual table-------------" << endl; vfun(); vfun = (Fun)*((int*)*((int*)(a))+1); vfun(); vfun = (Fun)*((int*)*((int*)(a)) + 2); vfun(); cout << "--------------------------------------" << endl; a->display(); a->v_display(); a->v_0_display(); ((B*)(a))->display(); ((B*)(a))->v_display(); ((B*)(a))->v_0_display(); b->display(); b->v_display(); b->v_0_display(); ((A*)(b))->display(); ((A*)(b))->v_display(); ((A*)(b))->v_0_display(); system("pause"); }
打印结果为:
the address the first virtual function is002FDC94 ------------virtual table------------- B::display A::v_display B::v_0_display -------------------------------------- B::display A::v_display B::v_0_display B::display A::v_display B::v_0_display B::display A::v_display B::v_0_display B::display A::v_display B::v_0_display 请按任意键继续. . .
标签:结合 存储 virt style cout 抽象类 抽象 子类 类型
原文地址:http://www.cnblogs.com/AkazaAkari/p/6182717.html