Ваш код "работает", потому что ни один из ваших методов 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()
в обычном режиме с параметром this
, установленным на указатель Person*
, который имеет тип -кастрируется до Student*
. Поскольку this
не разыменовывается about_me()
, вызов является «успешным» в том смысле, что вы видите «ожидаемый» результат. Неважно, на что this
указывает в этом случае, потому что он не используется.
Теперь попробуйте добавить некоторые элементы данных в ваши классы, а затем вывести эти элементы в about_me()
, и вы увидите очень разные, очень неожиданные / случайные результаты из-за неопределенного поведения, которое вы вызываете. Например:
class Person
{
protected:
string m_name;
public:
Person(const string &name)
: m_name(name)
{
cout << "Creating Person Class" << endl;
}
void about_me()
{
cout << "I am a person, my name is " << m_name << endl;
}
};
class Student : protected Person
{
private:
int m_id;
string m_school;
public:
Student(const string &name, int id, const string &school)
: Person(name), m_id(id), m_school(school)
{
cout << "Creating Student Class" << endl;
}
void about_me()
{
cout << "I am a student, my name is " << m_name << ", my id is " << m_id << " at " << m_school << endl;
}
};
int main()
{
Person* pperson = new Person("John Doe");
Student* pstudent = new Student("Jane Doe", 12345, "Some School");
pperson->about_me(); // "I am a person, my name is John Doe"
pstudent->about_me(); // "I am a student, my name is Jane Doe, my id is 12345 at Some School"
pperson->about_me(); // "I am a person, my name is John Doe"
((Student*)pperson)->about_me(); // runtime error!
delete pstudent;
delete pperson;
return 0;
}
Live Demo