2013-02-14 5 views
1

У меня есть базовый класс Student(), с двумя производными классами GradStudent() и UndergradStudent().C++ Создание массива из нескольких производных классов

Базовый класс имеет функцию 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

Это не работает? Похоже, должно. В чем проблема? (хотя делать это так глупо) – Pubby

+4

Пока 'getInfo' является' virtual' - это должно быть, так как он находится в базовом классе, который вы не можете изменить - это должно работать. В чем проблема? – Jon

+1

Покажите нам определения классов из Student, GradStudent и UndergradeStudent и укажите, что у вас есть с кодом –

ответ

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); 

Не забудьте удалить их в конце программы.

+0

Я на самом деле пытался сделать это таким образом, но компилятор бросил посадку, потому что у меня есть деструкторы. – user2036101

+0

Зачем ему бросать подгонку, потому что у вас есть деструкторы? – dutt

+0

huh. Просто попробовал еще раз, и это сработало. Наверное, я что-то изменил с тех пор, как прошёл последний раз, когда я это пробовал. (Поздно ... Я не думаю, что хорошо). Thnaks! – user2036101

2

Если вы не можете изменить даже производные классы, их невозможно вызвать из 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 - это хорошее место для дальнейшего ознакомления с виртуальными функциями.

+0

Почувствуйте мою боль. Половина вопросов на моих экзаменах - «Позвольте мне сделать самый неудобный, ужасно разработанный код и вы его прочитали». И все мои задания точно так же, как вы его описываете. Честно говоря, я ненавижу указатели и избегаю их, как чуму, но ... – user2036101

+0

Успокойся, когда я учился, однажды на одном большом коллоквиуме я получил исходный код с использованием неназначенной переменной. Это был самый забавный коллоквиум и единственный, когда я получил 110% доступных очков :) Удачи вам в экзаменах! – Spook

+0

Итак, вы не знаете, как бы вы дифференцировали вызов между getInfo() из базового класса и getInfo() из его фактического класса? Как именно виртуальное исправление вещей (И если слишком много, чтобы объяснить, не могли бы вы указать мне в правильном направлении?) – user2036101

0

Я немного смущен вопросом, но это то, что я получаю от него:

перебирать каждый элемент в classRoom, вызывая getInfo() по каждому элементу. Затем выведите результат test.getInfo() и ust1.getInfo().

Если это правильно, я считаю, что учитель может попытаться указать на то, что если объект, на котором getInfo() вызывается является одной из производных типов классов (GradStudent или UndergradStudent), даже если указатель на объект имеет тип Student*, всегда будет вызываться версия производных классов getInfo().

Это потому, что даже если вы звоните getInfo() на Student*, getInfo() связывается с производным реализации классов во время выполнения (поскольку getInfo() является виртуальным).

+0

На самом деле он говорит мне использовать один и тот же элемент массива из обеих функций getinfo() – user2036101

Смежные вопросы