I had a small Qt 3.3 utility that refreshed a list after reading a directory. It worked until I renamed a slot, at which point clicking the button did precisely nothing. No crash, no compiler error, just a very calm refusal to cooperate.

My naive fix was to add qDebug() calls everywhere except the place that mattered. The button emitted its signal and the refresh function worked when called directly. After too much staring, I finally checked the return value from connect() and ran the program with Qt warnings visible.

bool connected = connect(refreshButton, SIGNAL(clicked()),
                         this, SLOT(reloadDirectory()));
Q_ASSERT(connected);

The slot declaration and the string in SLOT() no longer agreed. Qt’s meta-object compiler records the signal and slot information that ordinary C++ does not provide. The connection is therefore checked at runtime, not by the compiler. Once I remembered that mechanism, the silence stopped being mysterious.

The generated meta-object code also explains why a class using signals or slots needs the Q_OBJECT macro and must pass through moc. Forgetting that step can produce linker errors rather than a friendly explanation. With the normal Qt build tools, the extra generation is automatic; with a handmade makefile, it is another dependency that must be stated correctly.

I tested disconnection and destruction as well. Qt removes connections involving a destroyed object, which is safer than retaining callbacks into dead C++ instances. That convenience still depends on the receiver actually being a QObject with a well-defined lifetime.

I now keep signals and slots in the appropriate class section, inspect the generated warnings, and assert important connections during development. I also avoid clever overloads unless they buy something substantial. The old string syntax is useful, but it can turn a typo into a tiny mime performance.

Small executable tests help here too: create the sender and receiver, emit once, and verify the resulting state before involving the whole window.

Qt 3.3 remains pleasant C++ because it removes a great deal of event plumbing. It does not remove the need to understand that plumbing. Framework convenience is best treated as compressed machinery: use it freely, but know where to open the panel when it stops.