0

I need the pointer to the specific object, that calls the method I'm in to compare the calling objects type to a specific type.

Here I cannot do it by using parent() and i cannot use sender() because the method is not called via signal/slot. Also it would take too much effort to pass the pointer as an argument because the "target" method is used by many classes and sometimes it's even used as a slot.

I need this for a big existing code so it's not a viable option to change the software structure. Sadly i have to deal with the software as it is.

void ClassA::callingFunction()
{
    AnyObject *obj = new AnyObject();
    obj->desiredMethod();
}

void ClassB::callingFunction()
{
    AnyObject *obj = new AnyObject();
    obj->desiredMethod();
}

void AnyObject::desiredMethod()
{
    QObject *callingObject = ?
    //Here i need a pointer to the instance of ClassA/ClassB which calls this method

    bool bTypeMatch = typeid(*callingObject) == typeid(ClassA);
    if(bTypeMatch) {...}
}
Otto V.
  • 169
  • 4
  • 11
  • What about `this`and a `dynamic_cast`, or am I missing something? – TheDarkKnight Apr 26 '16 at 09:51
  • by using `this`i get only the the pointer to the instance of `AnyObject` in my example but i need a pointer the instance of the object of `ClassA`/`ClassB` – Otto V. Apr 26 '16 at 09:53
  • That's the purpose of using [`dynamic_cast`](http://en.cppreference.com/w/cpp/language/dynamic_cast) – TheDarkKnight Apr 26 '16 at 09:57
  • I'm not sure if we talk about the same. I enhanced the comment in my code example to clarify what i need. – Otto V. Apr 26 '16 at 09:57
  • Oh, I see, you want pointer to the class of `callingFunction`. In which case, pass that into the `desiredMethod` function and dynamic cast to test which type called it. – TheDarkKnight Apr 26 '16 at 10:02
  • Now you got it. I can't simply change the argument list. I had that idea too, but it isn't a good solution because `desiredMethod()` is used by alot of different classes. So i would need alot changes in the software. – Otto V. Apr 26 '16 at 10:05
  • 2
    I believe there is no C++ / Qt method of doing this. If `AnyObject` were allocated on the stack, you would be able to use the architecture's calling convention and work out the address, but since it's on the heap, I don't think this is possible. Whilst you state `desiredMethod`is used by many classes, the easiest method is to change that, in this case. – TheDarkKnight Apr 26 '16 at 10:12
  • You may be able to use `backtrace()` on Linux, but AFAIK there's no portable way to do this, if not for the mentioned Qt facilities, or simply passing the pointer from the caller, or creating a separate method for each caller. – Murphy Apr 26 '16 at 10:25
  • @OttoV. can you change the invokation of `desiredMethod` from direct call to QMetaObject-based call? That way you'd be able to use `sender()` from within `desiredMethod`. – alediaferia Apr 26 '16 at 10:52
  • Is the problem that there are too many `AnyObject::desiredMethod` calls or `AnyObject` instances? Or even both? Would it be easier to modify the initialization of these objects? – thuga Apr 26 '16 at 11:34
  • @thuga too many method calls – Otto V. Apr 26 '16 at 11:40
  • So could you pass some value in the constructor of `AnyObject` to tell you which class is using `AnyObject`? Or maybe even create an abstract class? – thuga Apr 26 '16 at 11:42
  • @thuga i thought there is some simple trick for it, but now i will probably just overload the `desiredMethod()` and give the overloading one another argument. The software i have to work with is completely chaotic and bigger changes are pretty dangerous. This overload will be ugly, but no one will notice it in btween the rest of this "code". By the way I'm not the original autor. – Otto V. Apr 26 '16 at 11:46

4 Answers4

1

Pass in the ptr to the calling object and you can dynamic_cast to check its type

void AnyObject::desiredMethod(QObject* callingClassPtr)
{    
    ClassA* aPtr = dynamic_cast<ClassA*>(callingClassPtr);
    if(aPtr != nullptr) //nullptr in C++ 11
    {
        // I'm of type ClassA*
    }
}

Other than this, there is no other way of achieving your goal.

TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • Doesn't `this` return a pointer to the instance of `AnyObject`!? – Otto V. Apr 26 '16 at 10:01
  • Edited answer based on comments. – TheDarkKnight Apr 26 '16 at 10:05
  • I recently commented on the question, that this would work in theory but it's not simple to implement in my code. I also edited my question to include this restriction. – Otto V. Apr 26 '16 at 10:07
  • you cannot `dynamic_cast` from `void*`: [link](http://stackoverflow.com/questions/4131091/dynamic-cast-from-void) – Andrei R. Apr 26 '16 at 11:55
  • 1
    from question: `Also it would take too much effort to pass the pointer as an argument because the "target" method is used by many classes and sometimes it's even used as a slot.` - so this default value for argument or provide overloaded version so you could update code only in needed places. – Marek R Apr 26 '16 at 15:34
  • 1
    While `dynamic_cast` works, you can also use `qobject_cast` as that expresses your intent of casting the `QObject` type, and works even with no runtime type information support. – Kuba hasn't forgotten Monica Apr 26 '16 at 16:11
1

you can pass pointer of caller as QObject * and then either:

  1. check type name with QObject::metaObject()->className()
  2. check if object casts to required type by qobject_cast
  3. set additional class meta information width Q_CLASSINFO and check against it

Of course, to make it work you need either QObject-derived caller classes, or pointers to QObject.

Only thing i'm sure about is that you'll not be able to get pointer to caller from direct function call without sender parameters

Andrei R.
  • 2,374
  • 1
  • 13
  • 27
  • the *typeid*-stuff works fine.it looks like i'm forced to do an ugly overload which passes another argument (the pointer of calling object). – Otto V. Apr 26 '16 at 11:53
  • @OttoV. you can refactor it using `std::function` and `std::bind` techniques, yet I guess this is going to result in more drastic changes – Andrei R. Apr 26 '16 at 11:58
0

from question:

Also it would take too much effort to pass the pointer as an argument because the "target" method is used by many classes and sometimes it's even used as a slot.

So add default value for argument or provide overloaded version so you could update code only in needed places.

So improving answer from @TheDarkKnight IMO this could look like this:

void AnyObject::desiredMethod()
{
    desiredMethod(NULL);  //nullptr in C++ 11
}

void AnyObject::desiredMethod(ClassA* callingClassPtr) // not casting is not needed
{    
    if(callingClassPtr)
    {
         // extra action
    }
}
Marek R
  • 32,568
  • 6
  • 55
  • 140
0

This would be perhaps the only time where you have truly no choice but to call on the preprocessor to help you out. The desiredMethod is defined to be a fully qualified name, so that if the same method name is used elsewhere, it shouldn't compile and you'll be aware of the problem rather than facing possibly silent corruption of unrelated code.

Since desiredMethod is called with an argument of correct type, there's no reason to do any manual type casting. Instead, overload on the types you want to handle. If you want a default handler, you can implement desiredMethod(QObject * o): it'll catch all calls not handled by more specific overloads, since QObject is a base class of all the derived types you intend to handle.

#include <QtCore>

struct ClassA;
struct ClassB;

static enum { NONE, A, B } from = NONE;
struct AnyObject {
   void desiredMethod(ClassA *) { from = A; }
   void desiredMethod(ClassB *) { from = B; }
};

#define desiredMethod() ::AnyObject::desiredMethod(this)

struct ClassA : public QObject {
   void callingFunction() { AnyObject().desiredMethod(); }
};

struct ClassB : public QObject {
   void callingFunction() { AnyObject().desiredMethod(); }
};

int main() {
   ClassA a;
   ClassB b;
   Q_ASSERT(from == NONE);
   a.callingFunction();
   Q_ASSERT(from == A);
   b.callingFunction();
   Q_ASSERT(from == B);
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313