我有一组自定义类的Student对象。 CourseStudent和ResearchStudent都继承自Student,而Student的所有实例都是其中一个。
我有一个函数来遍历数组,确定每个Student的子类型,然后在它们上调用特定于子类型的成员函数。
问题是,因为这些函数没有重载,所以在Student中找不到它们,所以编译器会大惊小怪。
如果我有一个指向学生的指针,有没有办法获得指向该学生的子类型的指针?我是否需要在此处进行某种假冒操作以解决编译时错误?
答案 0 :(得分:10)
最好的方法是使用虚拟功能:
class Student
{
// ...
virtual void SpecificFunction() = 0; /* = 0 means it's abstract; it must be implemented by a subclass */
// ...
};
class CourseStudent
{
void SpecificFunction() { ... }
};
然后你可以这样做:
Student *student;
student->SpecificFunction();
更糟糕的替代方案可能是使用dynamic_cast
:
Student *student;
CourseStudent *cs = dynamic_cast<CourseStudent *>(student);
if (cs) {
/* student is a CourseStudent.. */
cs->SpecificFunction();
}
答案 1 :(得分:6)
你需要动态演员:
Student * s = new ...; // create student of some sort
if ( ResearchStudent * r = dynamic_cast<ReasearchStudent*>( s ) ) {
r->ResFunc();
}
else if ( CourseStudent * c = dynamic_cast<CourseStudent*>( s ) ) {
c->CourseFiunc();
}
else {
throw "unknown student type";
}
请注意,这使用了编译器维护的类型信息,前提是该类至少有一个虚函数 - 如果所有其他都失败,则使析构函数成为虚拟(因为它必须在这种情况下仍然是)。您应该始终更喜欢这种方法来维护自己的类型信息。
答案 2 :(得分:3)
虚拟函数在这里是不合适的,因为子类成员函数特定于那些子类(例如,CourseStudent有一个单元列表,而ResearchStudent没有,所以ResearchStudent中的getUnits()函数实现完全没有意义)
我对动态和静态强制转换(cplusplus.com typecasting)进行了一些阅读,在这种情况下,我认为静态强制转换更合适。
static_cast的一般缺点是它不会在运行时执行任何检查,以确保转换为子类型的对象实际上是该子类型而不是其他类型。在这种情况下,我在执行类型之前专门检查类型(使用在子类构造函数中设置的私有数据成员并且没有mutator),所以只要我的检查是好的,静态强制转换应该没有问题。静态强制转换更有效,因为动态强制转换需要更多的运行时资源来执行类型检查。
如果某个成员有可能不是预期类型,静态强制转换就不合适了,所以我会选择动态转换(这是一个赋值,所以一旦提交,代码就不需要维护了,所以以后没有人搞乱它的风险。)
答案 3 :(得分:2)
这几乎可以肯定是在基类中使用纯虚拟成员函数,然后覆盖执行实际工作的派生类。
答案 4 :(得分:1)
您需要static_cast
。由于这些函数不是基类的虚拟成员,因此无法通过指向基类的指针调用它们。您需要显式转换为对象的实际类型。
这个问题通常最好通过虚函数解决 - 你不再需要在代码中进行对象类型检查,代码更少,错误更少。