为什么从 base 转换为 derived 会提供此功能?
Why is casting from base to derived giving this functionality?
我很困惑为什么在我没有使用 virtual 关键字的情况下将派生的 class 转换为基 class 的指针会调用派生的 class 方法。这是正常行为吗?指针是否在内存中保存了一个 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
你的代码 "works" 因为你的 about_me()
方法都没有访问它们各自的 this
指针。
从技术上讲,您正在做的是 未定义的行为,因为 pperson
没有指向有效的 Student
对象,但您告诉编译器把它当作它是。所以字面上 任何事情 都可能发生。
在许多 常见编译器实现中,class 方法调用如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()
的第 4 次调用中,您指示编译器调用 Student::about_me()
而不是让它使用其 this
参数正常调用 Person::about_me()
设置为类型转换为 Student*
的 Person*
指针。由于 this
未被 about_me()
取消引用,因此调用是 "successful",因为您会看到 "expected" 输出。在这种情况下 this
指向什么并不重要,因为它没有被使用。
现在,尝试向您的 classes 添加一些数据成员,然后在 about_me()
中输出这些成员,您会看到非常不同的 unexpected/random 结果,由于您正在调用的未定义行为。例如:
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;
}
我很困惑为什么在我没有使用 virtual 关键字的情况下将派生的 class 转换为基 class 的指针会调用派生的 class 方法。这是正常行为吗?指针是否在内存中保存了一个 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
你的代码 "works" 因为你的 about_me()
方法都没有访问它们各自的 this
指针。
从技术上讲,您正在做的是 未定义的行为,因为 pperson
没有指向有效的 Student
对象,但您告诉编译器把它当作它是。所以字面上 任何事情 都可能发生。
在许多 常见编译器实现中,class 方法调用如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()
的第 4 次调用中,您指示编译器调用 Student::about_me()
而不是让它使用其 this
参数正常调用 Person::about_me()
设置为类型转换为 Student*
的 Person*
指针。由于 this
未被 about_me()
取消引用,因此调用是 "successful",因为您会看到 "expected" 输出。在这种情况下 this
指向什么并不重要,因为它没有被使用。
现在,尝试向您的 classes 添加一些数据成员,然后在 about_me()
中输出这些成员,您会看到非常不同的 unexpected/random 结果,由于您正在调用的未定义行为。例如:
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;
}