Accessing subclass members from a baseclass pointer C++
Asked Answered
S

5

7

I have an array of custom class Student objects. CourseStudent and ResearchStudent both inherit from Student, and all the instances of Student are one or the other of these.

I have a function to go through the array, determine the subtype of each Student, then call subtype-specific member functions on them.

The problem is, because these functions are not overloaded, they are not found in Student, so the compiler kicks up a fuss.

If I have a pointer to Student, is there a way to get a pointer to the subtype of that Student? Would I need to make some sort of fake cast here to get around the compile-time error?

Sarnen answered 1/4, 2010 at 10:59 Comment(0)
K
8

You need a dynamic cast:

Student * s = new ...;    // Create student of some sort.

if ( ResearchStudent * r = dynamic_cast<ReasearchStudent*>( s ) ) {
   r->ResFunc();
}
else if ( CourseStudent * c = dynamic_cast<CourseStudent*>( s ) ) {
   c->CourseFunc();
}
else {
   throw "Unknown student type.";
}

Note that this uses type information maintained by the compiler, provided the class has at least one virtual function - if all else fails, make the destructor virtual (as it must be in this case anyway). You should always prefer this approach to maintaining your own type information.

Kayne answered 1/4, 2010 at 11:3 Comment(0)
F
11

The best thing would be to use virtual functions:

class Student
{
   // ...
   virtual void SpecificFunction() = 0; /* = 0 means it's abstract; it must be implemented by a subclass */
   // ...
};

class CourseStudent
{
    void SpecificFunction() { ... }
};

Then you can do:

Student *student;
student->SpecificFunction();

A (worse) alternative can be using dynamic_cast:

Student *student;
CourseStudent *cs = dynamic_cast<CourseStudent *>(student);

if (cs) {
   /* student is a CourseStudent.. */
   cs->SpecificFunction();
}
Felonious answered 1/4, 2010 at 11:2 Comment(1)
All things being equal, the Java/C# perspective would say that the dynamic cast is better, because that way your pointer is typed the way you intend to use it, instead of being a Student for which a call to SpecificFunction() gives the CourseStudent return value. But I'm sure all things are not equal - so what's bad about using the dynamic cast?Sized
K
8

You need a dynamic cast:

Student * s = new ...;    // Create student of some sort.

if ( ResearchStudent * r = dynamic_cast<ReasearchStudent*>( s ) ) {
   r->ResFunc();
}
else if ( CourseStudent * c = dynamic_cast<CourseStudent*>( s ) ) {
   c->CourseFunc();
}
else {
   throw "Unknown student type.";
}

Note that this uses type information maintained by the compiler, provided the class has at least one virtual function - if all else fails, make the destructor virtual (as it must be in this case anyway). You should always prefer this approach to maintaining your own type information.

Kayne answered 1/4, 2010 at 11:3 Comment(0)
S
4

Virtual functions are inappropriate here because the subclass member functions are specific to those subclasses (for example the CourseStudent has a list of units, whereas a ResearchStudent does not, so a getUnits() function implementation in ResearchStudent would make no sense at all)

I had a bit of a read up on dynamic and static casts ( cplusplus.com typecasting ), and in this instance I think a static cast is more appropriate.

The general disadvantage of a static_cast is that it does not perform any checking at runtime to ensure that the object being cast to a subtype is in fact that subtype and not some other. In this case I am specifically checking the type before I perform the type (using a private data member that is set in the subclass constructor and has no mutator), so as long as my checking is good there should be no problem with a static cast. A static cast is more efficient since a dynamic cast requires more runtime resources to perform the type checking.

Where there is any chance of a member not being the expected type, static casting would not be appropriate so I would go for dynamic casting (this is an assignment so once it has been submitted the code won't need to be maintained, so there's no risk of someone messing it up later).

Sarnen answered 1/4, 2010 at 11:27 Comment(2)
I know this was a long time ago, but I wanted to say thanks; I was just facing a very similar problem today, and your answer provided me exactly the solution I needed!Dendriform
@Dendriform Glad to hear it's still useful - makes it worth the effort of searching for the idea solution.Sarnen
B
2

This is almost certainly a case for using a pure virtual member function in the base class, then overriding in the derived classes where you do the real work.

Berlinda answered 1/4, 2010 at 11:2 Comment(0)
T
1

You need static_cast for that. Since those functions are not virtual members of the base class you can't call them through a pointer-to-base-class pointer. You need to explicitly cast to the actual type of the object.

This problem is usually best solved with virtual functions - you'll not need the object type checking in your code anymore, will have less code and less surface for bugs.

Terceira answered 1/4, 2010 at 11:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.