首页 >社区问答列表 >c++ - 将基类指针赋给派生类的问题

c++ - 将基类指针赋给派生类的问题

将派生类地址赋给基类指针,也就是基类指针指派生类对象,也就是我们平时说的多态

但是反过来的时候,必须经过强制类型转换才可以编译通过,

下来直接代码:

#include<iostream>

usingnamespacestd;

class Base
{
public:
virtual void print()
{
    cout<<"base"<<endl;
}
};

class Derived:public Base
{
public:
void print()
{
cout<<"derived"<<endl;
}
};
int main(void)
{

Base * pb=newB ase();//定义基类指针

Derived * pd=(Derived*)pb;//赋值给派生类指针

pd->print();//调用基类的print输出base

pd->Derived::print();//调用派生类的print输出derived

return 0;
}

我想问问用pd->print()为什么调用的是基类的print

然后为什么将基类的virtual去掉之后,调用的便是派生类的print

  • 滿天的星座
  • 滿天的星座    2017-06-05 11:13:463楼

    调用哪个虚函数是由对象所指的虚函数表所决定的,当你 new Base()的时候pb所指向的虚函数表中的虚函数是Base的,用(Derived*)强制转化并没改变,而非虚函数主要根据指针类型,也就是说pd一开始就是Derived,所以用Derived的函数,成员函数在调用时其实是调用了this指针的。

    +0添加回复

  • 回复
  • 怪我咯
  • 怪我咯    2017-06-05 11:13:462楼

    The virtual specifier specifies that a non-static member function is virtual and supports dynamic binding. It may only appear in the decl-specifier-seq of the initial declaration of a non-static member function (i.e., when it is declared in the class definition).

    Virtual functions are member functions whose behavior can be overridden in derived classes.

    使用virtual的意思就是这个函数可以被子类override,使指向子类的父类指针不跟据指针本身的类别来调用这个函数,而(通过查虚函数表V-Table)调用被子类override后的函数。
    值得一提的是

    Base * pb=new Base();//定义基类指针
    Derived * pd=(Derived*)pb;//赋值给派生类指针

    这样写是不正确,至少也是不安全的,不应该将指向父类对象的父类指针赋给子类指针。

    此处的pd->print指向的是虚函数表中父类的的print,所以

    pd->print();                    //调用父类的print,输出base

    调用的是Base::print

    接下来

    pd->Derived::print();

    这是强行在父类对象上调用子类的函数(或者说以父类对象为this,强行调用虚函数表中的子类print),一般不推荐这么做。

    +0添加回复

  • 回复
  • 伊谢尔伦
  • 伊谢尔伦    2017-06-05 11:13:461楼

    还真是这样,刚运行了一下,确实很难理解。

    我说一下我的思路,不知道对不对,大家可以参考一下:

    第一种情况,写了virtual,如果成员函数加virtual,说明是动态绑定,只有在执行时候才会找到被调函数的地址。但是在哪里找呢?貌似每个对象的内存中都会存在一份虚表(也有说法是每个类有一份虚表,对象共享),因为你的Derived指针指向的是Base对象的那块内存,所以系统就去那块内存的虚表中找print函数,那块内存中虚表中的print函数的地址是Base类的print函数的地址,所以调用了基类的print函数

    第二种情况:把virtual给去了,那就不涉及动态绑定,函数的地址是编译时候确定的。编译时候函数地址怎么确定呢:是通过在源程序符号表中查找所得。那么主程序中pd->print(),很明显,pd是Derived类,pd->print()相当于Derived::print,那编译器就到Derived类中找喽,所以编译时期把pd->print()中print()的地址替换成Derived::print的地址,所以就调用了子类的print函数。

    不知道你明白我说啥不

    +0添加回复

  • 回复