Once you make a slot (a method) public, then you cannot prevent it being called directly. So the only solution is to make the slot private. But then you can only establish the connection from within the class. And therefore you need to pass the instance of the emitting class, e.g. in constructor.
class SomeReceiver: public QObject
{
Q_OBJECT
public:
explicit SomeReceiver(SomeEmitter *emitter, QObject *parent = nullptr) : QObject(parent)
{
connect(emitter, &SomeEmitter::someSignal, this, &SomeReceiver::someSlot);
}
private:
void someSlot() // you cannot call it directly from outside, it is private
{
// some stuff here ...
}
}
(Alternatively, instead of establishing the connection in a constructor, you can make a setter function which would take a pointer to emitter instance and establish the connection. But then there is a danger of this setter being called twice etc. So I would prefer using the constructor...)
You can use it like this:
auto emitter = new SomeEmitter();
auto receiver = new SomeReceiver(emitter);
The code above ensures calling via signals and slots.
And if you want the code to be executed in a secondary thread, then just move the receiver to that thread.
receiver->moveToThread(&someThread);
... and then every time you emit emitter's signal, the conected slot will always be executed in the thread. If you do not move it to secondary thread, it will be executed in the main/GUI thread.
To enforce you move this object to a thread, then you can also move it in the constructor (either by passing also a thread pointer to constructor or by creating a thread in it - but then you need to take care of all the thread destructuring). I would strongly not recommend this, this is extremely ugly design.
PS: If you want to really enforce that some code is run in a thread, then you should inherint from QThread
and override its run()
method. This is ALWAYS executed in the thread.