How do I safely call methods from another object?



  • In Java, there are 2 ways: A. use messages to trigger that object into doing your bidding. B. static keyword.

    Plan B needless to say is not so "safe".

    I wonder how things are done in C++? I want to do something that is a tad bit on the complicated side and yet the code was already done I just need to call it - but it's in another compilation unit so technically I'm not supposed to call it from "here".

    Someone please enlighten me?

    Quick recap:

    Object A want to do thing X. Object B already has a function that does precisely thing X.

    I want to execute that function from within A, which I shouldn't, what's the best workaround?



  • Hi, easiest is just to create an instance of Object B somewhere inside one of your Object A's functions and then call Object B's function using that instance of Object B, say something like:

    #include "ObjectA.h"
    #include "ObjectB.h"
    
    void ObjectA::functionA()
    {
       ...
        ObjectB b;
        b.functionB();
        ...
    }
    

    If the 2 objects are within the same compilation unit or not doesn't matter.

    P.S. That particular instance of ObjectB is shortlived and dies when functionA() exits, so if you want to remember some value or state from Object B you have to store it somewhere in Object A.



  • Thanks for the help.

    Sorry if I did not remember to clarify a few things.

    Object B is kind of resident (the main interface of the program), which means it pretty much lives as long as the program itself.

    It would be quite impossible for me to create B inside A.



  • Ok, if you're sure that Object B is alive all of the time, then one way is, instead of creating a new instance of Object B in Object A's function, you can pass around a pointer to that long-lived instance of Object B in your Object A's functions, say:

    #include "ObjectA.h"
    #include "ObjectB.h"
    
    void ObjectA::functionA(ObjectB* b)
    {
       ...
        b->functionB();
        ...
    }
    

    That means when you call ObjectA::functionA() you have to include that pointer, like:

    ,,,
    void ObjectA::someOtherFunction()
    {
        functionA(&longLivedInstanceOfB);
    }


  • But that's what I'm worried about: is that "safe"?

    C programs are usually fairly straight forward and light in weight. I'm not so inclined to throw pointers around in C++ as I did in C. It's way more complicated to me.



  • It's safe if you're sure that you're only calling it when Object B is alive and well. One simple safeguard is to check for null pointer before using it:

    oid ObjectA::functionA(ObjectB* b)
    {
        ...
        if (nullptr != b)
            b->functionB();
        ...
    }
    


  • Thanks. On a side note, can we use signal slots?

    Sender: object A

    Signal:some sort of customized signal

    target: object B

    Slot: well I dont know what slot in this scenario...



  • Sure, that's a great way to use signal and slots, they take care of that "object gone anxiety" for you, i.e. checking for null pointers and nasty stuff, like objects instanced in different threads etc.



  • @hskoglund Hi sounding totally like a cheapskate and lazybum, could you be kind enough to provide an example using object A and B? You may make up function C and D as you go. I can't thank you enough! :)


  • Moderators

    @JohnFrom
    I'm making use of @aha_1980 link collection thread

    and point you to the wiki page of the new signal sliot syntax, should give you everything you need to successfully connect to objects/classes:
    https://wiki.qt.io/New_Signal_Slot_Syntax

    and here the example form the docu:
    http://doc.qt.io/qt-5/signalsandslots.html#a-small-example



  • @JohnFrom I second @J-Hilk's post, that example from the docs is good, also there some signal/slot examples to be found in Qt Creator's Welcome pane as well.



  • @J.Hilk

    Thanks a whole bunch. This is how far I managed to get:

    connect(&sender, SIGNAL(newNodeAdded()), this, SLOT(addNewNodeBySignal()));

    where:

    sender is the signal sender object.

    newNodeAdded() is the void function declared after signal: in the relevant header file.

    "this" is the signal receiver, the object that's resident as I mentioned above.

    addNewNodeBySignal is the SLOT defined in the receiver's header file.

    Now I'm having the "sender not decleared in the scope" error, kind of right back where I started.

    Any smart workaround?


  • Qt Champions 2018

    @JohnFrom Can you show your code?
    You did not define sender in the context where you call connect.



  • @jsulm You are absolutely correct. I knew what it meant. I just don't know the right way to solve it, other than static pointers or objects, both sound like colossal bad ideas.

    Code-wise, I'll paste some here but it would be best if I provide some background:

    First of all the sender is purposed to be a service, so I'm not sure it's the best of ideas to have it inherit Qobject and become a sender, what I'm trying to say is maybe the better way is to define a dedicated object inside this service, with its soul purpose being communicating with the outside world. I'm not sure if that's a good idea either.

    The receiver on the other hand, is a typical Qobject, responsible for presenting the UI. So naturally it has tons of signals and slots.

    And without further ado, here is the code:
    Sender.h

    class Sender: public someService, public QObject
    {
    
         Q_OBJECT
    
    signals:
        void newNodeAdded();
    
    };
    

    Sender.cpp

    ```
    
    if( !node ){
            node = new node(nodeId, nodeId);
            TnodeStore.insertnode(node);
            TDatabase.addnode(node);
            emit newnodeAdded();
        }
    
    
    Receiver.h:
    
    
    

    class nodeView : public QWidget
    {
    Q_OBJECT

    private slots:

    void onRefreshnodeClicked(void);
    };

    
    
    Receiver.cpp:
    
    

    connect((QObject*)sender, SIGNAL(newNodeAdded()), this, SLOT(onRefreshnodeClicked()));

    
    
    
    Note this code was updated with some errors rectified.

  • Qt Champions 2018

    @JohnFrom said in How do I safely call methods from another object?:

    sender

    where is this "sender" defined?
    The code you posted does not help much as it is not complete.



  • @jsulm

    Sorry!

    The other parts of the code are really irrelevant and I don't want to have anything to do with the NDA so I'll have to pretty much manually quasi-obfuscate the code which is a lot of work.

    "sender" is defined just like what you read, in Sender.cpp and Sender.h

    I assume you were trying to say where it was instantiated? It's instantiated in a rather unconventional way:

    SenderService *sender = NULL;
        if( condition == A ){
            sender = new senderServiceA();
        }else if( condition == B ){
            sender = new senderServiceB();
        }else{
            qDebug() << "Invalid condition!";
        }
    

    Note that both senderServiceA and senderServiceB are "child classes" of SenderService.

    That code above was instantiated as an object in

    MainWindow class, which is a "child classes" of QMainWindow, and will be executed during run time.

    However it is quite impossible for the UI (that persistent object I mentioned above, lives as long as the program is running) to access this service object. Shall I write another object dedicated in interconnecting the 2 objects as some sort of proxy, or shall I embed this "communication object" inside one of the 2 objects?

    Or I should stick with basics, try to enable both objects to use slots? I'm reluctant to go down that route because I don't want either object to be able to directly access another and strangely enough, for object B to receive signal from object A, object A must be defined in the scope visible to B.


  • Qt Champions 2018

    @JohnFrom said in How do I safely call methods from another object?:

    SenderService *sender = NULL;

    sender here is a LOCAL variable!
    Do you call connect in same scope?
    Posting such small pieces of code makes it hard for others to understand what you do and where the problem is...


  • Moderators

    @JohnFrom said in How do I safely call methods from another object?:

    Or I should stick with basics, try to enable both objects to use slots? I'm reluctant to go down that route because I don't want either object to be able to directly access another and strangely enough, for object B to receive signal from object A, object A must be defined in the scope visible to B.

    whats that supposed to mean?

    For QObject::connect to work, at least the Sender-object needs to have QObject as its base class, sender and receiver, if you're using qt4 syntax.

    Also Signal & Slot connections do not violate c++ standards/rules, you can connect only to functions and/or slots outside the scope where connect is called, that are public.

    if object A lives in object C, and object B lives in object C, than you can use QObject::connect in object C to connect A & B without A knowing about B or visa versa.


  • Qt Champions 2018

    @J.Hilk I think the problem is that he declares sender als local variable and when he tries to connect "sender" is undefined. This kind of mistake is one of the most common here :-)


  • Moderators

    @jsulm possible, we simply don't know enough of the actual code to say for sure.

    However, am I wrong here, or is "xxxx not decleared in the scope error " not usually a sign of missing includes ?
    I tried to use connect on a null pointer recently.
    It compiled, it run, it did not crash, I only got a warning " cannot connect to nullptr".

    More infos needed!


  • Qt Champions 2018

    @J.Hilk

    connect((QObject*)sender, SIGNAL(newNodeAdded()), this, SLOT(onRefreshnodeClicked()));
    

    "sender not decleared in the scope"


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.