Detecting object type from base type (C++)

Started by
11 comments, last by jpetrie 16 years, 11 months ago
Consider the following sample:

#include <stdio.h>

struct FooA
{
};

struct FooB : public FooA
{
};

bool isFooB(const FooA* const foo)
{
	return // Return true if foo is of the type FooB else false
}

int
main(const int argCount, const char* const args[])
{
	FooA* a = new FooA;
	FooA* b = new FooB;
	if (isFooB(a))
		printf("a is FooB\n");
	if (isFooB(b))
		printf("b is FooB\n");
	return 0;
}


Is there any way that you could detect if the object foo in the function isFooB was created using FooA or FooB? The obvious easy solution is to add a new method: virtual bool isFooB(void) const; However, I'd very much like a solution that doesn't require that you need to add code (patching lot's of old stuff). It's ok to use some compiler specific hacks (using ICC8 atm), is it possible to examine the vtable pointer? Edit:

bool isFooB(const FooA* const foo)
{
	static const FooA a;
	return ((const int*)&a)[0] != ((const int*)foo)[0];
}

Would work for the above case, but my real problem is slighly more complicated I realized.
Advertisement
Hello!

I think the best solution to your problem is to use RTTI features of C++.
( Which normally is standardized and not compiler specific... )
It's allow you to determine a run time the type of a polymorphic object....

Try "RTTI c++" in google to get more informations .....

Hope it help ;)

Clement
Nitpick: You're using C++, so #include <cstdio> is more proper than that current form you've got.

typeid and dynamic_cast are your options here, besides the virtual method you've already suggested. All three are particularly brittle and most likely defeating the purpose of a having FooB derived from FooA (if you need to know the type; if that matters somehow, then you're probably violating a key object-oriented design tenant).

So I must ask, why do you need to know the actual type pointed to by a base class pointer? There's a very good chance there is a better way to approach that larger problem.
Yes, typeid is the way to go. Read here how to use it (last example):
http://www.cplusplus.com/doc/tutorial/typecasting.html


Quote:Original post by jpetrie
So I must ask, why do you need to know the actual type pointed to by a base class pointer? There's a very good chance there is a better way to approach that larger problem.


An example where you might need this can be found here (last paragraph):
http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=119&rl=1
You can do something that is called a 'downcast' because you are casting down the inheritance ladder. Use the dynamic_cast<T>(*p) keyword to achieve this effect. dynamic_cast will return NULL if the types are incompatible.

However, you should be warned that doing downcasts is usually an indication of bad design and that it takes a bit more performance than doing a static cast. Sometimes, however, its the easiest and cleanest way to find out about some objects inheritance. Forget about introducing type enums / ids as member variables, it's considered to be even worse.

Downcasts are not 'evil' and they are also not a performance-killer, so don't take the above information to seriously. However, you should always think twice before using them...
Quote:Nitpick: You're using C++, so #include <cstdio> is more proper than that current form you've got.

I knew it would come! :)
Quote:I think the best solution to your problem is to use RTTI features of C++.

I don't know that much about RTTI more than people telling me not to use it because it's slow etc.
Isn't it a bit of overkill to enable RTTI whn only used for a small sub-system?
Quote:So I must ask, why do you need to know the actual type pointed to by a base class pointer?

Well I don't exactly need to, but for the system that I'm doing now it would be very helpful.
Basicly it's something like a very lighweight factory.
I.e when saving an object I have something like this:
template <class T> void save(T* object);
The first thing stored is the type name of the object, then the object data is stored.
For loading I have something like this:
template <class T> T* load();
The loader reads the typename, looks it up in a map to find a creator function (that is pre-registered).
I could easily solve this by "forcing" all my objects to save the correct typename, but it's easier to mess up and requires more code.


Quote:
An example where you might need this can be found here (last paragraph):
http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=119&rl=1

I think that's an excruciatingly poor example, to be honest. I will of course admit to the fact that sometimes type-switching is acceptable. That example, however, is just poorly conceived as far real-world design concerns go; it's just there as a framework for explaining a use. There are a number of ways to handle that situation more elegantly and without relying on RTTI -- although its somewhat beyond the scope of this thread, they primarily involve around fixing the fundamental design flaws with TextFile and OnRightClick themselves, both of which appear to be designed to do far too much and couple together far too much functionality.

Quote:
I don't know that much about RTTI more than people telling me not to use it because it's slow etc.
Isn't it a bit of overkill to enable RTTI whn only used for a small sub-system?

People are silly. There is obviously a performance cost associated with it, yes. But it's generally not significant. Profiling of the specific situation is generally required to make that judgment. If you need RTTI, your only options are to use the built-in RTTI or roll your own, which would likely have all the same performance costs anyway; the only issue would be that you could control the impact and scope of those costs better. It's probably not worth worrying about.

Quote:
Well I don't exactly need to, but for the system that I'm doing now it would be very helpful.
Basicly it's something like a very lighweight factory.
I.e when saving an object I have something like this:
template <class T> void save(T* object);
The first thing stored is the type name of the object, then the object data is stored.
For loading I have something like this:
template <class T> T* load();
The loader reads the typename, looks it up in a map to find a creator function (that is pre-registered).
I could easily solve this by "forcing" all my objects to save the correct typename, but it's easier to mess up and requires more code.

Okay. A factory system has no need for RTTI or type-switching at all; in fact, to make a factory use either of them makes it a pretty poor factory implementation, because type-switching creates maintainability issues -- to extend the system, a case for a new type must be handled -- and avoiding that is one of the key benefits of most factories.

There are a number of articles around on creating abstract factory systems. Google can reveal a lot. Both libindustry and Loki have pretty powerful abstract factories that might be worth looking into.

In the most-general form, a factory is about creating a product based on a key. That key does not have to be the actual type of the object desired. Here's a simple example of such a system:

The primary interface to the factory will be called Factory. Factory will produce subclasses of Product on-demand, based on a key; it will do this by using the key as an index into a map of Producer subclasses (Producer is a class designed to, as the name implies, produce a Product). Factory will need a way of being informed about associations between concrete Producer instances. All told, Factory might look like:
class Factory{  std::map<std::string,Producer> producers;  public:    std::auto_ptr<Product> Create(const std::string& key)    {      return (std::auto_ptr(producers[key].ProduceInstance());    }    void RegisterProducer(std::string &key,Producer producer);    {      producers.insert(std::make_pair(key,producer));    }};

The interface for Producer should be implicit by the above definition:
class Producer{  public:    virtual Product* ProduceInstance() = 0;};

Product can look like whatever you want it to look like; its interface is relatively unimportant. Note that templates can be used to further generalize all this, but that might obscure my main points.

Now, to actually use this, you have to do three things:
1) Create a concrete Product subclass that you want to have created.
2) Create a concrete Producer subclass that does nothing but create a new instance of the desired concrete Product.
3) Register the Producer with the Factory.
It might look like:
class FooProducer : public Producer{  public:    Product* ProduceInstance() { return new Foo(); }};

main() might contain the registration and factory construction:
int main(){  Factory factory;  factory.RegisterProducer("fooKey",FooProducer());  Product *foo = factory.Create("fooKey");}


Now, the gut reaction among many is to argue that that since you have to create a new Producer subclass for every Product subclass, you're doing the same amount of work as with type-switching. That's true.

However, one of the big advantages here is that you can (with a big of extra work, such as using templates to remove specific dependencies on the base classes and key type) build yourself a generic abstract factory that is extended from client code, rather than the requiring modification (and recompiling, and redistribution, et cetera) of the library code where the factory resides. This reduces coupling and generally results in a cleaner design, since the client specifics (the concrete types) are located with the rest of the client code and not with the reusable framework code. You've also removed the need to write explicit logical tests and leverage both existing code and the language itself to do a lot of the tedious gruntwork of resolving the appropriate function calls.

Now, there are definitely improvements to be had: my example is, in the grand scheme of things, rather crude. I would encourage you to look into existing abstract factory implementations (again, libindustry and Loki are probably good places to start) and see how they're implemented; they employ a number of interesting and clever tricks, optimizations, and generalizations that result in much better production code than my ad-hoc example.

Anyways. I got a bit carried away by all that, some of which I'm sure you know, and didn't address your specific issue fully. The above principals can be applied to your situation, and it does sound like you've done so to at least some extent. For your load and save functions, presumably you have to call some method on the input object to actually get at the serializable data within that object (I hope you're not just writing the object's bits directly to a stream!). Since that enforces an interface on the type T anyway, you may as well continue to extend that interface to have it provide a method for getting the objects "serialization key" (which could in your case just be the name of the class). You'll have to manually provide the value of this key yourself, perhaps via a static method (you wouldn't necessarily want RTTI do that for you anyway, as the values of its type name strings are implementation dependent).

Your save function would then write the value of that key to the stream, followed by doing whatever actual serialization you require. Your load function would then read that key and give it to the factory (which would be more or less identical in spirit to my implementation, except it take a parameter in the Factory::Create() and Producer::ProduceInstance() methods that was the binary data read from the file that the actual object is to be deserialized from).

If you're doing generic serialization work, you might also want to examine Boost's serialization library. It's complex, but you might be able to get some ideas from it.

[Edited by - jpetrie on May 4, 2007 11:34:20 AM]
I quite aware on how to create factories, in fact I've used many such systems before.
Sorry for beeing so unclear.
What I'm having "trouble" with atm is not how to create the objects from an id (key).
The problem is sort of in the saving process, imagine:

std::vector<Thing*> m_things;

int i;
for (i = 0; i < m_things.size(); ++ i)
save(someOutput, m_things);


template <class T>
void save(SomeOutputClass* out, T* object)
{
writeObjectType(out, object); // How to determine id (key) here
object->save(out); // Objects must implement a save method
}

template <class T>
void writeObjectType(SomeOutputClass* out, T* object)
{
????
}

The easy workaround here is to write the id (key) in every objects save method.
It's not much fun to retro fit into the many classes that I have, so I'm trying to find a way to achieve this without it.
So it's not neccesary, just a lot more convinient..
I see. Oh well, maybe somebody will find that tirade of mine helpful. I really should start collecting all of my common responses someplace so I don't have to waste so much energy retyping them!

So your problem is essentially one of wanting to be able to produce a key string for a type without having to manually go around and do it for every class? It really doesn't seem like it matters if you modify every save() method to write the string or modify every type to add a getType() method and use that, either in save() or writeObjectType().

As I alluded to, RTTI's typeid() capability could be a solution to for doing this automatically. Except that the value of the string in the resulting type_info structure is implementation-dependent, and might not work out (especially if you need other compilers to compile code that can load these objects).

I think just biting the bullet and adding a method/static constant/line of code to the save() method/etc to every class is the best option. There are various tricks you could use to do it automatically but they tend to fall into one of two categories:
a) Either they involve extensive up-front work figuring out how to preprocess your code to generate the key (regex, Python or Perl program, how do find only the right places to insert the key, etc). A pain in the butt; might not be worth it versus the actual work of rote copy-paste-change-the-value work.
b) Or they generate the key automatically based on some ugly static initialization hackery or other crufy mucking about in almost-undefined-behavior-land. While the up-front work is possibly less, you've just made your classes have really nasty warts that will last a lot longer than the time you would have spent doing the manual insertion of the key into the save() method (or whatever).

A grim prospect. This is why I quit writing C++.

Well, not really. But its nice to be using a language that makes this a non-issue.
Quote:Or they generate the key automatically based on some ugly static initialization hackery or other

I already have a method for generating the key, I actually use some template magic to get the fully qualified typename, then I hash it to get a 32 bit id, works very well (too bad I can't get the compiler to transform it to a compile time constant though).
I think there's no way of doing what I wanted without enabling RTTI, so I guess I have to bite the bullit and do it the ugly but easy way...








This topic is closed to new replies.

Advertisement