C++跟我一起透彻理解虚函数表
2015-06-28 12:29
561 查看
//首先让我们来了解类对象的构造顺序。 #include <iostream> using namespace std; class A { public: A(){ cout << "A" << endl; } virtual void PrintfA() = 0; }; class B { public: B(){ cout << "B" << endl; } }; class C :virtual public A , public B { //关于构造对象顺序: //第一步先构造虚基类,例如此处的虚继承。 //第二步构造一般继承类,此处从左往右顺序执行。 //第三部构造成员变量,记住这里的成员变量的构造是顺序执行的。 //第四构造自身的构造函数。 public: C() { cout << "C" << endl; } void PrintfA() { cout << "hello word!!" << endl; } private: }; int main() { C c; return 0; }
#include <iostream> using namespace std; typedef void (*Pfun)(); class Base { public: virtual void Printf() { cout << "Base::Printf()" << endl; } void PrintfBae() { cout << "Base::PrintfBase" << endl; } }; class Son1:public Base { public: virtual void Printf() { cout << "Son1::Printf()" << endl; } void PrintfSon1() { cout << "Son1::PrintfSon1()" << endl; } }; class Son2 : public Son1 { public: void Printf() { cout << "Son2::Printf()" << endl; } virtual void hello() { cout << "hello" << endl; } void PrintfSon2() { cout << "Son2::Printf()" << endl; } }; int main() { Son2 s2; Base &b = s2; //b.Printf(); //此处可以得出这三个类维护了一个共同的虚表,但是我们还无法知道他们的 //具体位置以及各个类里面非虚函数的存储关系,所以我们接下来验证。 //Pfun fun = (Pfun)*((int *)(&(int*)&b)+1); Pfun fun = (Pfun)*((int *)*(int *)(int *)(&b) + 0); //这种做法基本没有人解释,所以我在后面用图解释了。 fun(); fun = (Pfun)*((int *)*(int *)(int *)(&b) + 1); fun(); //-------------------------------------------------------- fun = (Pfun)*((int *)*(int *)(int *)(&s2) + 0); fun(); fun = (Pfun)*((int *)*(int *)(int *)(&b) + 1); fun(); //打印结果与上面一样,可以得出这份虚表是所有继承该拥有虚表基类的成员类所共享的。 //每个对象的产生必定有两个数据,一个vptr指向虚表的指针,还有其自身的成员 //变量。 return 0; } //总结1:前提是基类是有虚表的,单一继承,所有的成员类与基类共同维护同一个虚表,各自有 //一个vptr指向这个虚表,子类如果会对虚表进行替换修改,具体会根据子类是否重载了基类的 //虚函数来确定,我们成为覆盖。多继承下面讨论,其实本质是一样的,关键问题是,多继承中 //子类中到底有几份虚vptr指针。
#include<iostream> using namespace std; class A { public: virtual void Printf() { cout << "A::Printf()" << endl; } virtual void PrintfA() { cout << "A::PrintfA()" << endl; } }; class B { public: virtual void PrintfB() { cout << "B::Printf()" << endl; } virtual void Printf() { cout << "B::Printf()" << endl; } }; class C : public A, public B { public: void Printf() { cout << "C::Printf()" << endl; } }; int main() { typedef void(*PFun)(); C c; PFun fun = (PFun)*((int *)*(int *)((int *)(&c)+0) + 0);//第一个虚表指针vptr。 fun();//此处覆盖了,调用的是C中的Printf(); fun = (PFun)* ((int *)*(int *)((int *)(&c) + 1) + 0);//第二个虚表指针vptr。 fun(); //此处还有一个亮点,就是为什么(int *)(int *)两次,这下你应该明白了吧,因为可能 //有多个虚指针,编译器做的很好了,如果不这样做编译会报错。 cout << sizeof(c) << endl;//终极测试结果8。 return 0; } //总结2:多继承中每一个基类都维护一张自己的虚表,而子类中每继承一个虚基类就会有存在一个 //指向该基类虚表的指针,以上代码测试结果是C对象中有两个vptr指针,一个指向A基类的虚表,一 //个指向B基类的虚表。
相关文章推荐
- 大话设计模式C++版——建造者模式
- 大话设计模式C++版——建造者模式
- Double-Checked Locking is Fixed In C++11
- C语言中~的用法
- 用递归方法求n阶勒让德多项式的值
- Hanoi(汉诺塔)问题。
- C++ and the Perils of Double-Checked Locking: Part II
- 编写一个程序,将字符数组s2中的全部字符复制到字符数组s1中。不用strcpy函数。
- 编一程序,将两个字符串连接起来,不要用strcat函数。
- 【设计模式】C++中的单例模式
- 有一行电文,已按下面规律译成密码
- c语言常见函数自编写
- 有一篇文章,共有3行文字,每行有10个字符。要求分别统计出其中英文大写字母、小写字母、数字、空格及其它字符的个数
- C/C++ sort函数的用法
- 找出一个二维数组中的鞍点,即该位置上的元素在该行上最大、在该列上最小。也可能没有鞍点。
- 将一个数组中的值按逆序重新存放。
- 有一个已排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中
- Eclipse+CDT+MinGw进行C&C++开发
- 文章标题
- C++ MPICH