虚函数地址问题的vcall
class Myclass{
public:
virtual void myfunc(){
}
virtual void myfunc2(){
}
}
int main(){
printf("Myclass:myfunc() = %p",&Myclass::myfunc); // x86 4字节
printf("Myclass:myfunc2() = %p",&Myclass::myfunc2); // x86 4字节
// 这里是实际的函数,但是函数调用时通过vcall中转了一下
// 所以这里打印的是vcall函数的地址
// vcall thunk 调整this指针用的偏移
// 跳转到真正的虚函数中去
Myclass *myclass = new Myclass(); // 这里存放的地址和上述地址不同
}
-------------------------------------------------------------------
静态类型与动态类型
class Base{
public:
}
class Derive :public Base{
public:
}
class Derive2: public Base{
public:
}
/*
静态类型: 对象定义时的类型 ,编译期间就能确定好
Base base; base 的静态类型时Base
Derive derive; derive 的静态类型时 Derive
Base *pbase; pbase 的静态类型时Base *
Base *pbase2 = new Derive(); pbase2 的静态类型时Base *
动态类型: 对象目前所指向的类型 运行时所指向的类型 一般只有指针和引用才有动态类型的说法
一般就都是指父类的指针或者引用, 另外动态类型在执行过程中可以改变
Base *pbase2 = new Derive(); 动态类型时Derive
Base *pbase; 至少目前没有动态类型 他没有指向任何对象
pbase = new Derive2() 这时候动态类型就是Derive2
*/
-------------------------------------------------------------------
静态绑定 : 绑定的时静态类型, 所对应的函数或者属性依赖与对象的静态类型 发生在编译期
动态绑定: 绑定的时多年柜台类型 所对应函数或者属性依赖于对象的动态绑定 发生在运行期
普通成员函数时静态绑定, 而虚函数时动态绑定
缺省参数一般是静态绑定
class Base{
public:
void myfunc(){
cout << "Base::myfunc()" <<endl;
}
}
class Derive :public Base{
public:
void myfunc(){
cout << "Derive::myfunc()" << endl;
}
}
class Derive2: public Base{
public:
}
int main (){
Derive derive;
Derive *pderive = &derive;
pderive->myfunc(); // Derive::myfunc()
Base *pbase = &derive;
pbase->myfunc(); // Base::myfunc()
// 这时候就是体现出普通成员函数时静态绑定 ,
// 这里到底调用时父类的myfunc 还是子类的myfunc 取决于调用者自身的静态类型
// 所以里调用Base的myfunc
// 结论 : 不应该在子类中重新定义一个继承来的非虚函数
}
class Base{
public:
void myfunc(){
cout << "Base::myfunc()" <<endl;
}
virtual void myvirfunc(){
cout << "Base::myvirfunc()" <<endl;
}
}
class Derive :public Base{
public:
void myfunc(){
cout << "Derive::myfunc()" << endl;
}
virtual void myvirfunc(){
cout << "Derive::myvirfunc()" <<endl;
}
}
class Derive2: public Base{
public:
}
int main (){
Derive derive;
Derive *pderive = &derive;
Base *pbase = &derive;
pbase->myfunc();
Base base;
pderive->myvirfunc();
pbase->myvirfunc();
pbase = &base;
pbase->myvirfunc();
// 虚函数是动态绑定 : pderive 绑定的时Derive所以调用Derive的myvirfunc()
// 同样 pbase 绑定的Base *pbase = &derive; 所以也是调用Derive的myvirfunc()
// 最后 pbase = &base; 调用的时Base的myvirfunc();
// 总结 myvirfunc() 是虚函数 这里到底执行哪个myvirfunc()取决于调用者的动态类型
}
class Base{
public:
void myfunc(){
cout << "Base::myfunc()" <<endl;
}
virtual void myvirfunc(int value = 1){
cout << "Base::myvirfunc(), value = "<< value <<endl;
}
}
class Derive :public Base{
public:
void myfunc(){
cout << "Derive::myfunc()" << endl;
}
virtual void myvirfunc(int value = 2){
cout << "Derive::myvirfunc(), value =" << value <<endl;
}
}
int main (){
Derive derive;
Derive *pderive = &derive;
Base *pbase = &derive;
pbase->myfunc();
Base base;
pderive->myvirfunc();
pbase->myvirfunc();
pbase = &base;
pbase->myvirfunc();
/*
Derive::myvirfunc() ,value = 2
Derive::myvirfunc() ,value = 1 // 执行了子类的虚函数值 value 却是1
Base::myvirfunc() ,value = 1
*/
//这时候就体现了 缺省参数 的静态绑定
}
// 总结: 多态性
多态性这个概念 分两个方面 但是有一点, 多态 必须存在虚函数 没有虚函数 就不可能存在多态 并且 调用虚函数
1.从代码实现上
当我们掉一个虚函数时, 走的是不是通过查询虚函数表来找到虚函数入口地址 然后去执行虚函数
那就是多态 如果不走这个途径 那就不是多态
class A{
public:
virtual void virfunc(){
}
}
int main(){
A *a = new A();
a->virfunc(); // 这就是多态
A a1;
a1.virfunc(); // 这不是多态
A *pa = &a;
pa->virfunc(); // 这个也是多态
}
2. 从表现形式上来说
有继承关系 ,有父类有子类 父类中必须有虚函数 (这意味着子类中一定有虚函数
派生类重写基类的虚函数
父类指针或者指向引用子类对象
当以父类指针或这引用调用子类中重写了的虚函数时候 我们就看出来多态
因为调用子类的虚函数