我有一个基类Student(),有两个派生类GradStudent()和UndergradStudent()。
基类有一个名为getInfo()的函数,这两个派生类有自己的getInfo()函数。
分配是创建一个学生数组并存储该数组中每个类的对象。然后我从每个调用getInfo()(使用每个的基类函数的版本),然后从两个派生类调用getInfo()函数。
对于我的生活,我无法弄清楚如何做到这一点。这是我到目前为止所做的:
(我想我应该在这里提一下,我不能修改基类)
Student *classRoom[3];
Student base ( "Jim", "Bean", 1111 );
classRoom[0] = &base;
GradStudent test ( "Jack", "Daniels", 1234, 'M', "Art" );
classRoom[1] = &test;
UndergradStudent ust1 ( "Johnny", "Walker", 1235, 1 );
classRoom[2] = &ust1;
cout << classRoom[1]->getInfo();
有人能指出我正确的方向吗?我会说具体的指令必须是一个数组,所以没有矢量解决方案请(仍然不熟悉它们)。
答案 0 :(得分:2)
如果你甚至无法修改派生类,就很难调用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
现在仔细阅读。如果Student::GetInfo
是虚拟的并且在GradStudent
类中实现,则GradStudent::GetInfo
将被调用,尽管事实上它会在Student
变量上调用。
但是,如果Student::GetInfo
不是虚拟,则在以前的情况下,将调用Student::GetInfo
。这基本上就是虚函数的工作原理。
在您的情况下,您有一系列Student *变量 - 您不确切知道它们是Student
,GradStudent
还是UndergradStudent
。由于您的Student::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是进一步了解虚拟功能的好地方。
答案 1 :(得分:0)
如果getInfo()
成员函数不是虚拟的,则作业的第一部分是迭代您的数组并在每个实例上调用getInfo()
。
对于第二部分,您必须将派生类的实例向下转换为它们的实际类型,以便调用派生类的实际成员函数。
另外,我建议您按以下方式填充阵列:
classRoom[0] = new Student( "Jim", "Bean", 1111 );
classRoom[1] = new GradStudent( "Jack", "Daniels", 1234, 'M', "Art" );
classRoom[2] = new UndergradStudent ( "Johnny", "Walker", 1235, 1 );
不要忘记在程序结束时删除它们。
答案 2 :(得分:0)
我对这个问题感到有些困惑,但这是我从中得到的:
遍历classRoom
中的每个元素,在每个元素上调用getInfo()
。然后输出test.getInfo()
和ust1.getInfo()
的结果。
如果这是正确的,我认为教师可能试图指出的是,如果调用getInfo()
的对象是派生类类型之一(GradStudent
或{ {1}}),即使指向对象的指针属于UndergradStudent
类型,也始终会调用Student*
的派生类版本。
这是因为即使您在getInfo()
上调用getInfo()
,Student*
也会在运行时绑定到派生类实现(因为getInfo()
是虚拟的)