Is it possible to have pure virtual slots?
-
I have a based class which creates several slots:
virtual void connected() = 0; virtual void dataIn() = 0; virtual void disconnected() = 0;
In my derived class I implement these slots:
void connected() override; void dataIn() override; void disconnected() override;
I'm asking if this is possible because since I've done this I'm getting some very odd behaviour which I cannot explain, execution is halting in internal Qt functions.
[Edit] I just read here:
https://stackoverflow.com/questions/2998216/does-qt-support-virtual-pure-slotsThat the answer is yes, but the override keyword is not required and the driver functions should not appear under a public slots section...but having done that I'm still getting:
'function name' overrides a member function but is not marked 'override'
For each overridden slot, this does not explain the strange behaviour.
-
@SPlatten , I moved the socket connection from the constructor to its own function:
void clsModHelper::connectToXMLMPAM() { //Connect to the Application connectToHost(clsModHelper::mscpszHost, muint16Port); if ( waitForConnected(clsModHelper::mscintConnectionTimeout) != true ) { throw -1; } }
main loops like this:
int main(int intArgc, char* parystrArgv[]) { //Initialise the module QApplication a(intArgc, parystrArgv); clsModFileIO obj(&a, intArgc, parystrArgv); try{ obj.connectToXMLMPAM(); } catch( exception& e) { std::cout << "Could not connect to XMLMPAM!"; exit(EXIT_FAILURE); } return obj.intExitCode(); }
Now it works, thank you to everyone who helped me to resolve this issue.
-
Hi,
What strange behavior do you get ?
-
@SGaist I had a break point on:
if ( waitForConnected(clsModHelper::mscintConnectionTimeout) ) {
I've set the mscintConnectionTimeout to 20000 ms. When I click on the step over icon, the debugger jumps into qobjectdefs_impl.h and stops on line 152:
(o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
-
What if you have a pure virtual with a default implementation ?
-
@SGaist , updated....if I comment out the 3 connects which:
// connect(this, &QTcpSocket::connected, this, &clsModHelper::connected); // connect(this, &QTcpSocket::disconnected, this, &clsModHelper::disconnected); // connect(this, &QIODevice::readyRead, this, &clsModHelper::dataIn);
It doesn't crash and the connection is made, waitForConnected doesn't crash and the application continues to where I expect.
To clarify, in the base class, the initial prototype for these slots:
public slots: virtual void connected() = 0; virtual void dataIn() = 0; virtual void disconnected() = 0;
Then in my derived class:
public slots: void connected() override; void dataIn() override; void disconnected() override;
The implementation, just to prove if works:
void clsModFileIO::connected() { //Start the module thread start(); } void clsModFileIO::dataIn() { qdbg() << "dataIn"; } void clsModFileIO::disconnected() { emit terminateModule(); }
If I then uncomment those connections and rebuild it does exactly the same its very repeatable.
-
I used to have pure virtual slots. It's quite a long time ago so I was using the old syntax to connect. Maybe you can try if that will work.
P.S. I think the "override" mark is irrelevant, you can add that. The SO post is so old that c++11 was not published at that time. -
@Bonnie , just replaced connections with:
connect(this, SIGNAL(connected), this, SLOT(connected)); connect(this, SIGNAL(disconnected), this, SLOT(disconnected)); connect(this, SIGNAL(readyRead), this, SLOT(dataIn));
It worked, no more crashing, thank you.
-
@SPlatten ok, than this
connect(this, &QTcpSocket::connected, this, &clsModHelper::connected);
is explicitly invoking the pure virtual base function, thats bound to crash
connect(this, &QTcpSocket::connected, this, & clsModFileIO::connected);
should work fine
-
@J-Hilk , thank you, but isn't this the point of using a pure virtual slot, I want the actual derived slot to be worked out by the compiler so I can have any number of derived classes based the same pure virtual slot and then the actual slot gets called in its place?
-
@Bonnie , not so fast, I thought it worked because it didn't crash, but now I see in the Application Output:
2020-11-06 09:11:49.460550+0000 mdFileIO[4406:86031] QObject::connect: Parentheses expected, signal clsModHelper::connected in ../mdFileIO/clsModHelper.cpp:67 2020-11-06 09:11:49.460576+0000 mdFileIO[4406:86031] QObject::connect: Parentheses expected, signal clsModHelper::disconnected in ../mdFileIO/clsModHelper.cpp:68 2020-11-06 09:11:49.460583+0000 mdFileIO[4406:86031] QObject::connect: Parentheses expected, signal clsModHelper::readyRead in ../mdFileIO/clsModHelper.cpp:69
-
@SPlatten
The old syntax is not like that :)
As the output says you need parentheses likeconnect(this, SIGNAL(connected()), this, SLOT(connected())); connect(this, SIGNAL(disconnected()), this, SLOT(disconnected())); connect(this, SIGNAL(readyRead()), this, SLOT(dataIn()));
-
@SPlatten sure, but you can always call the base implementation by implicitly invoking it and in many cases you want to do that.
take for example:
class BaseClass { public: virtual void functionA() { qDebug () << "A"; } }; class DerivedClass : public BaseClass{ public: void functionA() override {qDebug() << "B";} }; class DerivedClass2: public BaseClass { public: void functionA() override { BaseClass::functionA(); qDebug() << "B"; } }; int main (int argc, char *argv[]) { DerivedClass c1; DerivedClass2 c2; c1.functionA(); qDebug() << "----"; c2.functionA(); }
this outputs:
B ---- A B
where the 2nd class implicitly invokes the base implementation.