从C++基类指针访问子类成员

7
我有一个自定义类Student对象的数组。CourseStudent和ResearchStudent都继承自Student,而Student的所有实例都是这两者之一。
我有一个函数来遍历数组,确定每个Student的子类型,然后在它们上面调用特定于子类型的成员函数。
问题是,由于这些函数没有重载,它们在Student中找不到,所以编译器会发出警告。
如果我有一个指向Student的指针,有没有办法获取该Student的子类型的指针?我需要进行某种虚拟转换来解决编译时错误吗?
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();
}

所有事情都相等的话,Java/C#的观点会认为动态转换更好,因为这样你的指针类型与你打算使用它的方式相同,而不是一个“学生”,调用SpecificFunction()返回CourseStudent值。但我确定并非所有事情都相等 - 那么使用动态转换有什么问题呢? - ACK_stoverflow

8

您需要使用动态转换:

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.";
}

注意,这个方法使用编译器维护的类型信息,前提是类至少有一个虚函数——如果其他所有方法都失败了,那就将析构函数设为虚函数(在这种情况下必须这样做)。你应该始终优先使用这种方法来维护自己的类型信息。

4

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

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

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

如果存在任何成员不是预期类型的可能性,则不适用于静态转换,因此我会选择动态转换(这是一个分配,因此一旦提交代码,就不需要维护代码,因此不存在以后有人搞砸的风险)。


我知道这是很久以前的事了,但我想说声谢谢;今天我遇到了一个非常类似的问题,你的答案正好为我提供了需要的解决方案! - GarrickW
@GarrickW 很高兴听到它仍然有用 - 这让寻找最佳解决方案的努力变得更有价值。 - David Mason

2

这几乎肯定是在基类中使用纯虚成员函数的情况,然后在派生类中重写此函数以执行实际工作。


1

你需要使用 static_cast 。由于这些函数不是基类的虚成员,所以不能通过指向基类的指针调用它们。你需要显式地将对象类型强制转换为实际类型。

这个问题通常最好使用虚函数解决 - 你就不需要在代码中进行对象类型检查了,代码量会更少,出错的机会也会更小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接