Let's suppose there is a Base class and class A, B which are derived from Base class.
Then, can I find real class of instance pointed by pointer of Base Class?
Let's suppose there is a Base class and class A, B which are derived from Base class.
Then, can I find real class of instance pointed by pointer of Base Class?
I think RTTI is the answer you are looking for. typeid
and dynamic_cast
are your friends.
From an implementation perspective, you might use dynamic_cast
and check whether this cast returns NULL
or not.
Form a software design perspective, however, I think that in most cases the demand of requesting type information at runtime indicates a design problem. One might use type information to decide if a particular behaviour is available. But usually single classes do not reflect directly the existence of behaviour, especially if we consider that the class hierarchy is extensible. Usually one can get around this by simply "asking" the object if a particular behaviour is present or meaningful; One could also invoke the behaviour and trust in a meaningful default behaviour.
Let's take, for example, the "scrambled eggs problem". Consider that we have farms with animals and we want to check if a farmer might have scrambled eggs for breakfast. We might check if one of the animals is a chicken based on the runtime type of the animal:
class Animal;
class Chicken;
class Cow;
class Farm {
public:
Farm(initializer_list<Animal*> animals) : ownAnimals(animals) {};
bool farmerMightHaveScrambledEggs();
private:
vector<Animal*> ownAnimals;
};
bool Farm::farmerMightHaveScrambledEggs() {
for (Animal* f : ownAnimals) {
if (dynamic_cast<Chicken*>(f))
return true;
}
return false;
};
This works quite well; but once we find out that not every chicken actually lays eggs, and if we consider that an ostrich (which is not a chicken) provide eggs that are used for scrambled eggs, this code fails. This would require to adapt the code, and if we did the check only class based, one might have to introduce classes just for the sake of deciding the scrambled-eggs topic. And classes like "EggLayingBirds" or even "BirdsLayingEggsForScrambledEggs" sound very artificial at the level of types.
So a better way is probably to express the semantics "provides eggs for scrambled eggs" using a member function reflecting this behaviour.
class Animal {
public:
// the very most animals do not provide eggs one might use for scrambled eggs:
virtual bool providesEggsForScrambledEggs() { return false; }
};
class Cow : public Animal {
};
class Chicken : public Animal {
virtual bool providesEggsForScrambledEggs() { return true; }
};
class Ostrich : public Animal {
virtual bool providesEggsForScrambledEggs() { return true; }
};
bool Farm::farmerMightHaveScrambledEggs_behaviourBased() {
for (Animal* f : ownAnimals) {
if (f->providesEggsForScrambledEggs())
return true;
}
return false;
};
bool Farm::farmerMightHaveScrambledEggs_classBased() {
for (Animal* f : ownAnimals) {
if (dynamic_cast<Chicken*>(f))
return true;
}
return false;
};
void checkFarmForScrabmledEggs(Farm &f) {
cout << "farmer might have scrambled eggs: " << f.farmerMightHaveScrambledEggs_behaviourBased() << endl;
cout << "farmer might have scrambled eggs: " << f.farmerMightHaveScrambledEggs_classBased() << endl;
}
int main(int argc, char* argv[]) {
Chicken aChicken;
Cow aCow;
Farm farmWithChicken ( { &aChicken, &aCow } ); // some eggs
Farm farmWithCowOnly( { &aCow } ); // no eggs
Ostrich anOstrich;
Farm australianFarm( { &anOstrich } ); // special eggs
checkFarmForScrabmledEggs(farmWithChicken); // both checks OK
checkFarmForScrabmledEggs(farmWithCowOnly); // both checks OK
checkFarmForScrabmledEggs(australianFarm); // class based check fails.
return 0;
}
One can further optimise the code by introducing data members at a particular place in the class hierarchy, like, for example, bool providesEggsForScrambledEggs;
to get even more independent of the class hierarchy. But these things are left to the reader :-)
Hope it helps a bit.