96

I understand how to use it, but the syntax of it bothers me. What is "private slots:" doing?

I have never seen something between the private keyword and the : in a class definition before. Is there some fancy C++ magic going on here?

And example here:

 #include <QObject>

 class Counter : public QObject
 {
     Q_OBJECT

 public:
     Counter() { m_value = 0; }

     int value() const { return m_value; }

 public slots:
     void setValue(int value);

 ...
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Justin
  • 2,322
  • 1
  • 16
  • 22
  • 4
    This is not Standard C++, This is QT framework construct. Lookup *QT signals and slots*. – Alok Save Feb 05 '12 at 07:21
  • 3
    When compiling as C++ `slots` is defined as `#define slots`. When compiling using Qt MOC it generates code for the C++ compiler. – dalle Feb 05 '12 at 08:17
  • 2
    lol this was even harder for me to understand because i havent used C++ in so long, i thought they added something new – dtc Nov 05 '15 at 17:55

4 Answers4

61

Slots are a Qt-specific extension of C++. It only compiles after sending the code through Qt's preprocessor, the Meta-Object Compiler (moc). See http://doc.qt.io/qt-5/moc.html for documentation.

Edit: As Frank points out, moc is only required for linking. The extra keywords are #defined away with the standard preprocessor.

Christophe Weis
  • 2,518
  • 4
  • 28
  • 32
Russell Davis
  • 8,319
  • 4
  • 40
  • 41
  • Thanks, Qt's preprocessor is what I was missing in my mental model of what was going on. – Justin Feb 05 '12 at 09:49
  • 18
    Not correct, the code compiles all the time as "signals" and "slots" are empty defines so the compiler never sees them. These macros are hints for moc, which generates _additional_ code. The original .h and .cpp files are not altered and compile just fine without moc. What would fail is linking, as the moc-generated definitions (signal definitions, metaobject, etc.) are otherwise missing. – Frank Osterfeld Feb 05 '12 at 17:33
  • 2
    Is the `slots` keyword necessary? I've tried compiling/linking a few tiny Qt programs that call slots without the `slots` keyword and they have built just fine. My experiments show that: `signals:` is definitely necessary, `slots` might be unnecessary, and `emit` seems to be unnecessary as I've read elsewhere. –  May 18 '14 at 03:20
  • 5
    `slots` is not necessary in Qt5. Qt updated the `connect()` syntax to allow for connecting a signal to an arbitrary function, including lambdas. Because of this, `slots` is not necessary. However, the `slots` keyword still affects the way that an object's `QMetaObject` is built. `moc` (aka, the "meta-object compiler") won't recognize a method as a slot unless it is within the `slots:` section of a class definition. So, although the connection will still work, the method will not show up in introspection tools. – Chris May 18 '17 at 21:32
22

The keywords such as public, private are ignored for Qt slots. All slots are actually public and can be connected

Andrew
  • 24,218
  • 13
  • 61
  • 90
  • 32
    When the method is called via signal/slot mechanism, the access specifiers are ignored. But slots are also "normal" methods. When you call them using the traditional way, the access specifiers are considered. – borges Feb 05 '12 at 15:58
  • 4
    @borges and any future readers. In Qt5 the connect() method can use function pointers (which has advantages). If you connect with function pointers then the access specifiers are enforced in the signals/slots mechanism. – Tod Feb 18 '14 at 04:42
  • 3
    @borges I believe this is incorrect, or at least the explanation was unclear. The access specifiers do not restrict your ability to connect signals to slots; that is, a private slot can be connected to *any* signal. The access specifier does, however, protect the member function from its class (in the typical way) while it's being invoked. So, the access specifiers aren't "ignored" when called via the signal/slot mechanism: they have no bearing on connecting slots to signals, but they do protect the function from `this` in the way we are familiar with. –  May 18 '14 at 03:18
4

Declaring slots as private means that you won't be able to reference them from context in which they are private, like any other method. Consequently you won't be able to pass private slots address to connect.

If you declare signal as private you are saying that only this class can manage it but function member pointers do not have access restrictions:

class A{
    private:
    void e(){

    }
    public:
    auto getPointer(){
        return &A::e;   
    }
};

int main()
{
    A a;
    auto P=a.getPointer();
    (a.*P)();
}

Other than that, what other answers mention is valid too:
- you still can connect private signals and slots from outside with tricks
- signals and slots are empty macros and do not break language standard

Euri Pinhollow
  • 332
  • 2
  • 17
  • Why does this question not have any upvotes? Is there something wrong with it? I find the statement, that `slots` is a macro helpful. I cannot connect private slot-function-pointers to `connect` without tricks, can I? – ArchLinuxTux Feb 09 '18 at 11:00
  • @ArchLinuxTux [function member pointers do not have access restrictions](http://coliru.stacked-crooked.com/a/19702602fb87e01e). – Euri Pinhollow Feb 10 '18 at 00:01
  • I think "Consequently you won't be able to pass private slots address to connect." contradicts @Andrew answer (which I think is the clearest), isn't? – KcFnMi May 28 '22 at 04:08
  • @KcFnMi you can connect any signals and slots you want regardless of their relationship between each other - if you have their pointers. That does not change the fact that you cannot reference private slots and signals by their identifier when they are not visible. I do not remember exactly but even using text strings as identifiers probably does not work either. – Euri Pinhollow Jul 08 '22 at 17:59
  • Because it expands into the reference to the actual signal or slot requested. – Euri Pinhollow Jul 19 '22 at 21:58
1

If we are going to call slots using the connect mechanism, then we declare them as public slots.

If we are not going to call them using the connect mechanism, then we do not declare them as slots.

If we are considering to call them both ways, may be its time for refactoring to fit in previous cases.

That's how I used to think.

Throughout the Qt documentation I see them as public. Just spot one place though where private slots are mentioned

Note: You need to include the QTest header and declare the test functions as private slots so the test framework finds and executes it.

KcFnMi
  • 5,516
  • 10
  • 62
  • 136