C++跟我一起透彻理解虚函数表
//首先让我们来了解类对象的构造顺序。
#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++:头文件的作用【头文件放函数声明,当源文件需要这些函数时,可以通过宏命令“#include”将该头文件包含进来,就可以使用头文件对应的具体函数了】
- C++-STL-组件(一)-容器04:deque(双端动态数组)
- [C++]2-3 倒三角形
- c++find函数用法
- C++中string erase函数的使用
- C++ 冒泡排序与sort函数
- C++ accumulate()函数
- VC++ 比较字符串是否相等的函数strcmp和wcscmp
- C++ 成员函数赋值给C 的函数指针的采坑录
- C++面向对象程序设计的一些知识点(5)
- C++默认参数与函数重载 注意事项
- 关于C++中的友元函数的总结
- C++ 获取类成员函数地址方法 浅析
- VC++ WIN32 sdk实现按钮自绘详解.
- C++字符串之一(字符表示)
- C/C++源代码的Include依赖关系图
- 10.C++-构造函数初始化列表、显示初始化和隐式初始化、类const成员、对象构造顺序、析构函数
- C++文件操作
- C++异常处理
- C++:继承与多态补充 | 静态联编时确定了哪些属性 | free和delete混用问题 | 虚析构函数问题
- 在Windows下用Eclipse+CDT+MinGW搭建C++开发平台