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

时间:2013-08-06 07:21:23

标签: c++ c++11

我对上传有疑问。 考虑有两个类,Class Parent和Class child。孩子继承了父母。

问题:

如果我为父项创建对象指针,并指定了子对象引用。我遵守了。输出是“对象切片”。无法访问子类特定组件

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。如果我在父类中创建goToPlay()的虚函数,则可以访问它。任何人都可以说出原因吗?

3 个答案:

答案 0 :(得分:1)

由于您的指针类型为Parent,因此只能访问Parent的api,因为这是您告诉编译器的内容。 (即此指针指向Parent个对象)。

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

答案 1 :(得分:1)

您明确声明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会在运行时发生这种情况,并会降低应用程序的速度。尽可能避免使用它。

答案 2 :(得分:1)

为了通过指向Child::goToPlay()的指针使用ParentParent必须声明自己的函数goToPlay(),并且必须标记此函数virtual。然后,您的Child课程将覆盖该职能。

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

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