虚函数调用中的指针类型转换以及指针所指类型的本质

  父类类型指针可指向子类对象,调用子类对象重写的虚函数,一条代码即有了不同的表现结果,也就是多态。

  很显然,子类重写的虚函数里调用的自然是子类的成员变量,父类类型指针是无法直接访问到子类的成员变量的。那么既然是父类类型指针调用的子类的虚函数,那么传给this的自然就是父类类型的指针,那么又如何能访问到子类的成员变量呢?

  细心想一下就明白了,this指针也是有类型的,其类型就是类本身类型,所以子类的虚函数中,this指针的类型就是子类类型,因此当父类类型的指针作为实参传进去时,会强制转换成子类类型指针,这样就能正确访问子类成员变量。

  如代码所示:

Child child;
Parent *p = &child;

//如果print()是子类重写的虚函数,那么完整的print()的类型是:
//virtual void print(Child *this);
//p将强制转换成Child*类型,然后初始化this
p->print();

  这里另一个实质性的问题就是,为什么父类指针已经指向了子类对象,却不能直接访问其成员变量呢?这是因为指针的解引用的结果在本质上,就是一块固定内存空间的大小。父类和子类所占内存大小一般不一样,因此解引用了父类类型指针,得到的内存空间并不是子类的内存空间。只有将父类类型指针类型强行转换成子类类型的指针,那么解引用指针后,得到的就是子类对象的内存空间了,也就可以合法访问子类内存空间中的成员变量了。

  知道了这一点,就可以用间接的方法,使指向子类对象的父类类型指针访问子类的成员变量了。如代码:

class Parent
{
public:
    int a;

};

class Child : public Parent
{
public:
    int b;

};

int main()
{
    Child child;
    child.b = 10;

    Parent *p = &child;

    //child对象中继承的parent成员变量统统位于栈底,这是因为构造函数先初始化父类
    //因此p+1即得到子类成员变量的首地址,即通过了父类类型指针,得到了子类对象的成员变量
    int tmp = *((int*)(p+1));

    //tmp将是10
    cout << "tmp=" << tmp << endl;

    return 0;
}

  配以图示:

原文地址:https://www.cnblogs.com/demon90s/p/4663743.html