当子对象引用被分配给父对象指针时,为什么不能访问子类

Why couldnt access the child class when child object reference is assigned to parent object pointer

本文关键字:为什么 不能 子类 访问 指针 对象 对象引用 分配      更新时间:2023-10-16

我对升级有疑问。考虑有两个类,类父类和类子类。子代已与父代一起继承。

问题:

如果我为父对象创建对象指针,并指定子对象引用。我照做了,结果是"对象切片"。无法访问子类特定组件

class Parent
{
public:
    int i;
    void school()
    {
        std::cout<<"Parent Class::School()"<<std::endl;
    }
    // virtual goToPlay()
    // {
    //       std::cout<<"Parent Class::goToPlay()"<<std::endl;
    // }    
 };
class Child:public Parent
{
public:
    int j;
    void goToPlay()
    {
        std::cout<<"Child Class::goToPlay()"<<std::endl;
    }
};
int main()
{
    Parent *mParent;
    Child mChild;
    mParent = &mChild;
    mParent->school();
    mParent->goToPlay(); //Error

无法访问goToPlay()API。如果我在Parent Class中创建了一个虚拟函数goToPlay(),那么它是可以访问的。有人能说出原因吗?

您显式声明Parent * mParent,因此您的对象被视为Parent的实例。在许多用例中,这正是你想要的——你为做某事提供了一个合适的接口,而具体使用的实现与最终用户无关:

class employee
{
    public:
        virtual double get_salary_in_usd() const = 0;
        virtual ~employee() {}
};
class software_developer : public employee
{
    public:
        double get_salary_in_usd() const { return 100000.; /* i wish */ }
        void be_awesome() {}
        ~software_developer() {}
};
void print_salary(std::shared_ptr<employee> const & emp)
{
    std::cout << "This employee earns $" << emp->get_salary_in_usd()
              << " a month." << 'n';
}

然而,在某些情况下,您需要在运行时判断您的指针是否是基类的某个子级。这就是dynamic_cast的作用:

software_developer me;
employee * me_generalized = &me;
software_developer * me_again = dynamic_cast<software_developer *>(
    me_generalized);
if(me_again != nullptr)
{
    me_again->be_awesome();
}

注意,如果指针不能被广播,则dynamic_cast可以返回nullptr。还要注意,RTTI在运行时会发生这种情况,并降低应用程序的速度。尽可能避免使用此选项。

由于您的指针类型是Parent,因此只有Parent的api可以访问,因为这是您告诉编译器的。(即,该指针指向Parent对象)。

在您的情况下,virtual方法将进行正确的实现调用。(这被称为后期绑定,在运行时通过实例中的隐藏表来找到方法实现的正确地址,在您的情况下是Child实现,因为mParent指向Child实例)

为了通过指向-Parent的指针使用Child::goToPlay()Parent必须声明自己的函数goToPlay(),并且该函数必须标记为virtual。然后,Child类将覆盖该函数。

然后,当您在Parent指针上调用goToPlay()时,会神奇地调用Child函数。

但是,不能只对Parent中不存在的任意函数执行此操作。