user2036101
user2036101

Reputation: 75

C++ Creating an array of multiple derived classes

I have a base class Student(), with two derived classes GradStudent() and UndergradStudent().

The base class has a function called getInfo(), the two derived classes have their own getInfo() functions.

The assignment is to create an array of student and store an object of each class in that array. I'm then to call getInfo() from each (Using the base class function's version for each), then call the getInfo() function from the two derived classes.

For the life of me I can't figure out how to do this. Here's what I have so far:

(I guess I should mention here, I cannot modify the base class)

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

Can anyone point me in the right direction? I will say that the instructions specifically it has to be an array, so no vector solutions please (Still not familiar with them anyway).

Upvotes: 1

Views: 4876

Answers (3)

Spook
Spook

Reputation: 25929

If you cannot modify even the derived classes, it's hard to call GetInfo on them not knowing, that they are of specific type. Maybe you are required to use direct solution:

GradStudent gradStudent;
cout << gradStudent.GetInfo();

Or you can try to check, if a student is of specified derived class, but IMO it's extremely ugly and dangerous (in terms of extending the code):

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

I have to say, that polymorphism is created specifically to handle situations like this and GetInfo not being virtual in base class is serious architectural flaw.

Additionally: if you are playing with pointers, avoid retreiving addresses to local variables. That may be dangerous. Instead, allocate and deallocate the memory manually:

classRoom[0] = new Student;
classRoom[1] = new GradStudent;
classRoom[2] = new UndergradStudent;

// Process data

for (int i = 0; i < 3; i++)
    delete classRoom[i];

On the margin: I hate tasks like: Do X without using Y (where Y is specifically designed to solve X).


Edit: (in response to comments)

You asked, how virtual function would resolve the problem. Suppose for a moment, that Student::GetInfo is virtual. Let's analyse the following pieces of code:

Student * student = new Student;
student->GetInfo(); // Student::GetInfo is called

GradStudent * gradStudent = new GradStudent;
gradStudent->GetInfo(); // GradStudent::GetInfo is called

Nothing suprising, for now.

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

Now read carefully. If Student::GetInfo is virtual and is implemented in GradStudent class, GradStudent::GetInfo will be called, despite fact, that it is called on Student variable. However, if Student::GetInfo is not virtual, in previous case, Student::GetInfo will be called. This is basically how virtual functions work.

In your case, you have an array of Student * variables - you don't exactly know, whether they are Students, GradStudents or UndergradStudents. Since your Student::GetInfo is not virtual, calling this method on these variables will always result in calling Student::GetInfo, regardless of their actual type.

In such case the only solution I can think of is trying to guess, which class actually they are:

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

This way you can return to the original type and call GetInfo of the actual variable type.

Note though, that this is an ugly solution and this kind of problems is solved by virtual functions.

The C++ FAQ is a good place to read further about virtual functions.

Upvotes: 2

uberclops
uberclops

Reputation: 161

I'm a little confused by the question, but this is what I get from it:

Iterate through each element in classRoom, calling getInfo() on each element. Then output the result of test.getInfo() and ust1.getInfo().

If that is correct, I think what the teacher may be trying to point out is that if the object on which getInfo() is being called is of one of the derived class types (GradStudent or UndergradStudent), even though the pointer to the object is of type Student*, the derived classes version of getInfo() will always be called.

This is because even though you are calling getInfo() on a Student*, getInfo() will bind to the derived classes implementation at run-time (because getInfo() is virtual).

Upvotes: 0

Opera
Opera

Reputation: 983

If the getInfo() member function is not virtual, the first part of your assignment is to iterate on your array and call getInfo() on each of the instances.

For the second part, you will have to downcast the instance of the derived class into their real type in order to call the actual member function of the derived class.

Also I recommend you fill your array in the following way :

classRoom[0] = new Student( "Jim", "Bean", 1111 );
classRoom[1] = new GradStudent( "Jack", "Daniels", 1234, 'M', "Art" );
classRoom[2] = new UndergradStudent ( "Johnny", "Walker", 1235, 1 );

Don't forget to delete them at the end of your program.

Upvotes: 0

Related Questions