如果您甚至无法修改派生类,则很难在不知道它们是特定类型的情况下对它们调用 GetInfo。也许您需要使用直接解决方案:
GradStudent gradStudent;
cout << gradStudent.GetInfo();
或者您可以尝试检查学生是否属于指定的派生类,但 IMO 它非常丑陋和危险(就扩展代码而言):
for (int i = 0; i < 3; i++)
{
GradStudent * gs = dynamic_cast<GradStudent *>(classRoom[i]);
if (gs != nullptr)
cout << gs->GetInfo();
else
{
UndergradStudent * ugs = dynamic_cast<UndergradStudent *>(classRoom[i]);
if (ugs != nullptr)
cout << ugs->GetInfo();
else
cout << classRoom[i]->GetInfo();
}
}
我不得不说,多态性是专门为处理这种情况而创建的,而 GetInfo 在基类中不是虚拟的是严重的架构缺陷。
另外:如果您正在使用指针,请避免将地址检索到局部变量。那可能很危险。相反,手动分配和释放内存:
classRoom[0] = new Student;
classRoom[1] = new GradStudent;
classRoom[2] = new UndergradStudent;
// Process data
for (int i = 0; i < 3; i++)
delete classRoom[i];
在边缘:我讨厌这样的任务:做 X 而不使用 Y(其中 Y 是专门为解决 X 而设计的)。
编辑:(回应评论)
你问,虚函数如何解决这个问题。假设一下,那Student::GetInfo
是虚拟的。我们来分析以下几段代码:
Student * student = new Student;
student->GetInfo(); // Student::GetInfo is called
GradStudent * gradStudent = new GradStudent;
gradStudent->GetInfo(); // GradStudent::GetInfo is called
暂时没有什么大惊小怪的。
Student * student = new GradStudent;
student->GetInfo();
// if Student::GetInfo is virtual, GradStudent::GetInfo is called here
// if Student::GetInfo is not virtual, Student::GetInfo is called here
现在仔细阅读。IfStudent::GetInfo
是虚拟的并且在GradStudent
类中实现,GradStudent::GetInfo
将被调用,尽管事实上它是在Student
变量上调用的。但是,如果Student::GetInfo
不是 virtual,在以前的情况下,Student::GetInfo
将被调用。这基本上就是虚函数的工作方式。
在您的情况下,您有一组 Student * 变量 - 您不完全知道它们是Student
s、GradStudent
s 还是UndergradStudent
s。由于 yourStudent::GetInfo
不是虚拟的,因此对这些变量调用此方法将始终导致调用Student::GetInfo
,而不管它们的实际类型如何。
在这种情况下,我能想到的唯一解决方案是尝试猜测它们实际上是哪个类:
Student * student = new UndergradStudent;
Student * s = student; // Ok
GradStudent * gs = dynamic_cast<GradStudent *>(student); // Not true, will return NULL/nullptr
UndergradStudent * ugs = dynamic_cast<UndergradStudent *>(student); // Ok
这样就可以返回原来的类型,调用GetInfo
实际的变量类型。
但请注意,这是一个丑陋的解决方案,这类问题是由虚函数解决的。
C++ FAQ是进一步阅读虚函数的好地方。