Is it possible to have pure virtual slots?
-
@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. -
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 , thank you, the only reason I put in the override keyword is to get rid of the annoying yellow text appended at the end of each line suggesting it.
-
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
-
@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?
-
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 , 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 -
@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
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())); -
@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?
@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 Bwhere the 2nd class implicitly invokes the base implementation.
-
@Bonnie, its different, but still not right, now it stops in moc_clsModHelper.cpp on a line which reads:
case 4: _t->connected(); break;The Application Output shows:
libc++abi.dylib: Pure virtual function called! -
@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 Bwhere the 2nd class implicitly invokes the base implementation.
-
@Bonnie , sure:
These are very much a work in progress:
clsModHelper.h
class clsModHelper : public QTcpSocket { Q_OBJECT protected: bool mblnExit; double mdblVersion; FILE* mfpDbgLog; qint64 mint64AppPID; std::thread* mpHeartbeat; std::thread* mpThread; static const int mscintConnectionTimeout; static const int mscintHeartbeatFrequency; static const char* mscpszHost; static clsModHelper* mspThis; static char msszTitle[MODULE_NAME_LENGTH + 1]; quint16 muint16Port, muint16LauncherPID, muint16SleepTime; static bool blnToThisModule(clsJSON& objJSON); void cleanup(); void loopUntilExit(); void start(); public slots: virtual void connected() = 0; virtual void dataIn() = 0; virtual void disconnected() = 0; void errorOccurred(QAbstractSocket::SocketError socketError); void exitModule(); void killThreads(); public: static const char mscszAck[] ,mscszCmdHB[] ,mscszCommand[] ,mscszCommands[] ,mscszError[] ,mscszModule[] ,mscszMsgType[] ,mscszPID[] ,mscszResult[] ,mscszSkipOver[] ,mscszTime[] ,mscszTrue[] ,mscszType[] ,mscszTypeChar[] ,mscszTypeDouble[] ,mscszTypeFloat[] ,mscszTypeInt[] ,mscszTypeLong[] ,mscszTypeShort[] ,mscszTypeString[] ,mscszTypeUChar[] ,mscszTypeUInt[] ,mscszTypeULong[] ,mscszTypeUShort[]; explicit clsModHelper(QObject* pParent, int intArgc, char* parystrArgv[] ,const char* cpszTitle, double dblVersion); virtual ~clsModHelper(); double dblGetVersion() { return mdblVersion; } [[noreturn]] static void exitMsg(const char* cpszMsg ,const char* cpszPrefix = "ERROR" ,int intCode = EXIT_FAILURE); qint64 int64GetPID() { return mint64AppPID; } int intExitCode() { return 0; } static long lngTimeInSecs(); static clsModHelper* psGetModuleInstance() { return clsModHelper::mspThis; } static const char* cpszGetTitle() { return msszTitle; } void queueJSON(QJsonObject& objJSON); void sendHeartbeat(); void setSleepTime(quint16 uint16SleepTime) { muint16SleepTime = uint16SleepTime; } void threadBody(); virtual void moduleThreadBody() = 0; quint16 uint16GetLauncherPID() { return muint16LauncherPID; } signals: void onFailure(QJsonObject& objCmd); void onSuccess(QJsonObject& objCmd); void terminateModule(); void threadTerminated(); };clsModFileIO.h:
class clsModFileIO : public clsModHelper { private: static clsModFileIO* mspInstance; void cmdLineSummary(); public: static const char mscszCheck[] ,mscszCmdFind[] ,mscszCmdRead[] ,mscszCmdSave[] ,mscszCmdTell[] ,mscszCmdWrite[] ,mscszByteOrder[] ,mscszData[] ,mscszFailed[] ,mscszFile[] ,mscszFrom[] ,mscszLength[] ,mscszMode[] ,mscszModeBinary[] ,mscszModeText[] ,mscszPattern[] ,mscszPosition[] ,mscszStart[] ,mscszSuccess[]; explicit clsModFileIO(QObject* pParent, int intArgc, char* parystrArgv[]); ~clsModFileIO(); bool doCommand(QString& strFile, QJsonObject& objRequest , QJsonObject& objCmd , QJsonObject& objResponse , quint16 uint16Idx = 0); void moduleThreadBody() override; static clsModFileIO* pInstance() { return mspInstance; } public slots: void connected() override; void dataIn() override; void disconnected() override; void onFailure(QJsonObject& objCmd); void onSuccess(QJsonObject& objCmd); };Some additional information:
Qt Creator 4.13.2 Based on Qt 5.15.1 (Clang 11.0 (Apple), 64 bit) Built on Oct 1 2020 01:16:45 From revision 2ee1af2032Using Qt 5.15.0
-
@Bonnie , sure:
These are very much a work in progress:
clsModHelper.h
class clsModHelper : public QTcpSocket { Q_OBJECT protected: bool mblnExit; double mdblVersion; FILE* mfpDbgLog; qint64 mint64AppPID; std::thread* mpHeartbeat; std::thread* mpThread; static const int mscintConnectionTimeout; static const int mscintHeartbeatFrequency; static const char* mscpszHost; static clsModHelper* mspThis; static char msszTitle[MODULE_NAME_LENGTH + 1]; quint16 muint16Port, muint16LauncherPID, muint16SleepTime; static bool blnToThisModule(clsJSON& objJSON); void cleanup(); void loopUntilExit(); void start(); public slots: virtual void connected() = 0; virtual void dataIn() = 0; virtual void disconnected() = 0; void errorOccurred(QAbstractSocket::SocketError socketError); void exitModule(); void killThreads(); public: static const char mscszAck[] ,mscszCmdHB[] ,mscszCommand[] ,mscszCommands[] ,mscszError[] ,mscszModule[] ,mscszMsgType[] ,mscszPID[] ,mscszResult[] ,mscszSkipOver[] ,mscszTime[] ,mscszTrue[] ,mscszType[] ,mscszTypeChar[] ,mscszTypeDouble[] ,mscszTypeFloat[] ,mscszTypeInt[] ,mscszTypeLong[] ,mscszTypeShort[] ,mscszTypeString[] ,mscszTypeUChar[] ,mscszTypeUInt[] ,mscszTypeULong[] ,mscszTypeUShort[]; explicit clsModHelper(QObject* pParent, int intArgc, char* parystrArgv[] ,const char* cpszTitle, double dblVersion); virtual ~clsModHelper(); double dblGetVersion() { return mdblVersion; } [[noreturn]] static void exitMsg(const char* cpszMsg ,const char* cpszPrefix = "ERROR" ,int intCode = EXIT_FAILURE); qint64 int64GetPID() { return mint64AppPID; } int intExitCode() { return 0; } static long lngTimeInSecs(); static clsModHelper* psGetModuleInstance() { return clsModHelper::mspThis; } static const char* cpszGetTitle() { return msszTitle; } void queueJSON(QJsonObject& objJSON); void sendHeartbeat(); void setSleepTime(quint16 uint16SleepTime) { muint16SleepTime = uint16SleepTime; } void threadBody(); virtual void moduleThreadBody() = 0; quint16 uint16GetLauncherPID() { return muint16LauncherPID; } signals: void onFailure(QJsonObject& objCmd); void onSuccess(QJsonObject& objCmd); void terminateModule(); void threadTerminated(); };clsModFileIO.h:
class clsModFileIO : public clsModHelper { private: static clsModFileIO* mspInstance; void cmdLineSummary(); public: static const char mscszCheck[] ,mscszCmdFind[] ,mscszCmdRead[] ,mscszCmdSave[] ,mscszCmdTell[] ,mscszCmdWrite[] ,mscszByteOrder[] ,mscszData[] ,mscszFailed[] ,mscszFile[] ,mscszFrom[] ,mscszLength[] ,mscszMode[] ,mscszModeBinary[] ,mscszModeText[] ,mscszPattern[] ,mscszPosition[] ,mscszStart[] ,mscszSuccess[]; explicit clsModFileIO(QObject* pParent, int intArgc, char* parystrArgv[]); ~clsModFileIO(); bool doCommand(QString& strFile, QJsonObject& objRequest , QJsonObject& objCmd , QJsonObject& objResponse , quint16 uint16Idx = 0); void moduleThreadBody() override; static clsModFileIO* pInstance() { return mspInstance; } public slots: void connected() override; void dataIn() override; void disconnected() override; void onFailure(QJsonObject& objCmd); void onSuccess(QJsonObject& objCmd); };Some additional information:
Qt Creator 4.13.2 Based on Qt 5.15.1 (Clang 11.0 (Apple), 64 bit) Built on Oct 1 2020 01:16:45 From revision 2ee1af2032Using Qt 5.15.0
@SPlatten
As I remember, the overridden "slots" in the derived class can't be declared as slots.
So trypublic: void connected() override; void dataIn() override; void disconnected() override; public slots: void onFailure(QJsonObject& objCmd); void onSuccess(QJsonObject& objCmd);BTW, you don't have Q_OBJECT in clsModFileIO class but you can declare slots in it? Is that possible?
-
@SPlatten
As I remember, the overridden "slots" in the derived class can't be declared as slots.
So trypublic: void connected() override; void dataIn() override; void disconnected() override; public slots: void onFailure(QJsonObject& objCmd); void onSuccess(QJsonObject& objCmd);BTW, you don't have Q_OBJECT in clsModFileIO class but you can declare slots in it? Is that possible?
-
@J-Hilk Its a pure virtual slot for the purpose of defining the structure and interface required to be implemented by the derived classes, thats why they have no implementation.