为什么从基数转换为派生具有此功能?

时间:2018-09-04 23:47:45

标签: c++ casting base derived

当我没有使用virtual关键字时,为什么将派生类强制转换为基类的指针时会感到困惑。这是正常行为吗?指针不是在内存中保存了Person对象,因此将其强制转换为Student不会对其内容产生任何影响?

  class Person {

    public:

    Person()
    {
        cout << "Creating Person Class" << endl;
    }

    void about_me()
    {
        cout << "I am a person" << endl;
    }
};

class Student : protected Person {
    public:
    Student()
    {
        cout << "Creating Student Class" << endl;
    }

    void about_me()
    {
        cout << " I am a student " << endl;
    }

};

int main()
{
    Person* pperson = new Person();
    Student* pstudent = new Student();

    pperson->about_me();
    pstudent->about_me();

    pperson-> about_me();

    ((Student*)pperson)-> about_me(); // this is the line where I do the cast

    return 0;

}

代码输出如下

  Creating Person Class
Creating Person Class
Creating Student Class
I am a person
 I am a student 
I am a person
 I am a student

1 个答案:

答案 0 :(得分:4)

您的代码“有效”,因为您的about_me()方法都没有访问它们各自的this指针以获取任何内容。

从技术上讲,您正在执行的操作是未定义的行为,因为pperson并不指向有效的Student对象,但是您告诉编译器将其视为如果是的话。因此,任何事情都可能发生。

许多常见的编译器实现中,像pperson->about_me()这样的类方法调用实际上更像about_me(pperson)那样调用,其中about_me()被实现为具有this输入参数。因此,您已经展示了可能的代码可能是由编译器在幕后实现的(并非完全如此,但您应该明白这一点):

struct Person
{
};

void Person_Person(Person *this)
{
    cout << "Creating Person Class" << endl;
}

void Person_about_me(Person *this)
{
    cout << "I am a person" << endl;
}

struct Student
{
};

void Student_Student(Student *this)
{
    Person_Person(this);
    cout << "Creating Student Class" << endl;
}

void Student_about_me(Student *this)
{
    cout << " I am a student " << endl;
}

int main()
{
    //Person* pperson = new Person();
    byte *buf1 = new byte[sizeof(Person)];
    Person* pperson = (Person*) buf1;
    Person_Person(pperson);

    //Student* pstudent = new Student();
    byte *buf2 = new byte[sizeof(Student)];
    Student* pstudent = (Student*) buf2;
    Student_Student(pstudent);

    //pperson->about_me();
    Person_about_me(pperson);

    //pstudent->about_me();
    Student_about_me(pstudent);

    //pperson-> about_me();
    Person_about_me(pperson);

    //((Student*)pperson)-> about_me();
    Student_about_me((Student*)pperson);

    return 0;
}

因此,在对about_me()的第四次调用中,您正在指示编译器调用Student::about_me(),而不是让其通常将Person::about_me()的{​​{1}}参数设置为{类型转换为this的{​​{1}}指针。由于Person*未取消对Student*的引用,因此该调用是“成功的”,因为您会看到“预期的”输出。在这种情况下,this指向什么都没有关系,因为没有使用它。

现在,尝试将一些数据成员添加到您的类中,然后在about_me()中输出这些成员,由于调用的未定义行为,您将看到非常不同,非常意外/随机的结果。例如:

this

Live Demo