6

我有一组自定义类学生对象。CourseStudent 和 ResearchStudent 都继承自 Student,Student 的所有实例都是其中之一。

我有一个函数来遍历数组,确定每个学生的子类型,然后在它们上调用特定于子类型的成员函数。

问题是,因为这些函数没有重载,所以在Student中是找不到的,所以编译器就大惊小怪了。

如果我有一个指向 Student 的指针,有没有办法获得指向该 Student 子类型的指针?我需要在这里做一些假演员来解决编译时错误吗?

4

5 回答 5

11

最好的办法是使用虚函数:

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();
}
于 2010-04-01T11:02:22.630 回答
7

你需要一个动态演员:

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->CourseFunc();
}
else {
   throw "Unknown student type.";
}

请注意,这使用编译器维护的类型信息,前提是该类至少有一个虚函数 - 如果所有其他方法都失败,则将析构函数设为虚拟(无论如何它必须是这种情况)。您应该始终更喜欢这种方法来维护您自己的类型信息。

于 2010-04-01T11:03:24.673 回答
3

虚函数在这里是不合适的,因为子类成员函数特定于这些子类(例如 CourseStudent 有一个单元列表,而 ResearchStudent 没有,所以 ResearchStudent 中的 getUnits() 函数实现根本没有意义)

我对动态和静态转换(cplusplus.com typecasting)进行了一些阅读,在这种情况下,我认为静态转换更合适。

static_cast 的一般缺点是它在运行时不执行任何检查以确保被强制转换为子类型的对象实际上是该子类型而不是其他子类型。在这种情况下,我在执行类型之前专门检查类型(使用在子类构造函数中设置且没有修改器的私有数据成员),所以只要我的检查是好的,静态转换应该没有问题. 静态转换更有效,因为动态转换需要更多运行时资源来执行类型检查。

如果成员有可能不是预期的类型,则静态转换不合适,因此我会进行动态转换(这是一项任务,因此一旦提交,就不需要维护代码,所以有以后不会有人把它搞砸的风险)。

于 2010-04-01T11:27:52.717 回答
2

这几乎可以肯定是在基类中使用纯虚成员函数,然后在派生类中覆盖您进行实际工作的情况。

于 2010-04-01T11:02:18.713 回答
1

你需要static_cast那个。由于这些函数不是基类的虚拟成员,因此您不能通过指向基类的指针调用它们。您需要显式转换为对象的实际类型。

这个问题通常最好用虚函数来解决——你不再需要在你的代码中检查对象类型,将有更少的代码和更少的错误表面。

于 2010-04-01T11:01:27.860 回答