Если вы не можете изменить даже производные классы, их невозможно вызвать из GetInfo, не зная, что они имеют определенный тип. Может быть, вы должны использовать прямое решение:
GradStudent gradStudent;
cout << gradStudent.GetInfo();
Или вы можете попробовать, чтобы проверить, если студент из указанного производного класса, но ИМО это очень некрасиво и опасно (в плане расширения кода):
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];
На полях: я ненавижу такие задачи, как: Do X без использования Y (где Y является специально предназначен для решения X).
Edit: (в ответ на комментарии)
Вы спросили, как виртуальная функция будет решить эту проблему. Предположим на мгновение, что 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
, то, несмотря на то, что он вызывается на переменной Student
, будет называться GradStudent::GetInfo
. Однако, если Student::GetInfo
не является виртуальным, в предыдущем случае Student::GetInfo
будет называться. Это как раз то, как работают виртуальные функции.
В вашем случае, у вас есть массив Student * переменные - вы точно не знаете, являются ли они Student
s, GradStudent
s или UndergradStudent
s. Поскольку ваш 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 - это хорошее место для дальнейшего ознакомления с виртуальными функциями.
Это не работает? Похоже, должно. В чем проблема? (хотя делать это так глупо) – Pubby
Пока 'getInfo' является' virtual' - это должно быть, так как он находится в базовом классе, который вы не можете изменить - это должно работать. В чем проблема? – Jon
Покажите нам определения классов из Student, GradStudent и UndergradeStudent и укажите, что у вас есть с кодом –