This is exactly what dynamic_cast is for:
void SomeMethod(QObject *ptr) {
A *a = dynamic_cast<A *>(ptr);
if (a) { DoStuffA(a); return; }
B *b = dynamic_cast<B *>(ptr);
if (b) { DoStuffB(b); return; }
C *c = dynamic_cast<C *>(ptr);
if (c) { DoStuffC(c); return; }
DoStuffNOTA(ptr);
}
Since you're using Qt, you'd probably want to use qobject_cast instead of dynamic_cast,* but otherwise everything is the same.
However, all that repetition is, as usually, a sign that you're doing something wrong. You can eliminate a lot of it by using templates, but usually, you usually don't want to do this at all. Instead, use the "double dispatch" (aka "reverse dispatch") pattern.
The whole reason we have virtual functions, and OO in general, is to avoid type switching. The problem is that virtual functions (the way C++ does them) only dispatch on the this object: Foo::SomeMethod(QObject *) can be overridden for subclasses of Foo, but not for subclasses of QObject. But you can just add a method to QObject—or, in this case, to an intemediate class (or a multiple-inheritance mixin, if that isn't possible)—that all of your real classes can override:
class ClassIntermediate: public QObject {
public:
virtual void DoSomeMethodStuff() = 0;
};
class ClassA : public ClassIntermediate {
public:
virtual void DoSomeMethodStuff() { /* DoStuffA code here */ }
// all the stuff you were already doing in ClassA as a QObject
};
// likewise for ClassB and ClassC
class Foo {
void SomeMethod(ClassIntermediate *ptr) { ptr->DoSomeMethodStuff(); }
};
If there's some work that has to be done for all types, leave it in SomeMethod, before or after the call to DoSomeMethodStuff. (If that work is intermixed with the subclass-specific stuff, and you can't rearrange it, just factor out multiple methods to double-dispatch to instead of just one.)
If the code needs the Foo object's this pointer, just pass it as an argument to DoSomeMethodStuff.
If you need to handle any QObject, not just your subclasses, then you may want to use a single dynamic_cast<ClassIntermediate *> and double-dispatch to that.
So, why is this better than type switching? Today, you have three classes, and one method that switches on them. If you add another method tomorrow, you have to write the same 3-way type switch again. If you then add a fourth class, you have to remember to go back and edit them both. If you end up with N classes and M methods that have to switch on them, you've written N*M blocks of code instead of N+M. All that extra code isn't just annoying; it virtually guarantees that you're going to miss one of the edits one day, leading to a painful debugging problem.
The main advantage of qobject_cast is that Qt provides its own, more extensive, RTTI system than what's built in to C++, and it's possible to build Qt without C++ RTTI at all (or, on Windows, in such a way that classes in different DLLs can be connected up via Qt RTTI but not C++ RTTI), and qobject_cast will still work.