":connect' error - "multiple definition..." ?
-
wrote on 11 Jan 2023, 18:50 last edited by
I am trying to pass messages between classes.
He is my TEST code - just trying to activate "connect" in same class..I followed intelisenses building the “connect” , so I do not need any comments about not using new lambda format UNLESS the old format is causing the error.
I need help to find why the compiler / linker is saying I have
multiple definition of `BT_ChatServer::NewMessage()';
I just want the code to compile and link, the SIGNAL and SLOT has no code...just debug stuff
signals:
void NewMessage();
void messageReceived(const QString &sender, const QString &message);
void clientConnected(const QString &name);
void clientDisconnected(const QString &name);private slots:
void PostMessage();
void clientConnected();
void clientDisconnected();
void readSocket();void BT_ChatServer::PostMessage()
{
qDebug() << Q_FUNC_INFO;
text = "\n\t TASK Run \n"; // + Q_FUNC_INFO;
text += Q_FUNC_INFO;
text += "\n";
qDebug() << text;}
void BT_ChatServer::NewMessage()
{
qDebug() << Q_FUNC_INFO;
text = "\n\t TASK Run \n"; // + Q_FUNC_INFO;
text += Q_FUNC_INFO;
text += "\n";
qDebug() << text;#endif
}// passing message temp to same class f
connect(this,SIGNAL(NewMessage()),
this,SLOT(PostMessage()));
// emit newMessage();here is the error
QtCore -I. -I/usr/include/libdrm -I/home/nov25-1/Qt/Nov26/5.15.2/gcc_64/mkspecs/linux-clang -o main.o main.cpp
/usr/bin/ld: /usr/bin/ld: DWARF error: invalid or unhandled FORM value: 0x23
moc_chatserver_BT_copy.o: in functionBT_ChatServer::NewMessage()': moc_chatserver_BT_copy.cpp:(.text+0x250): multiple definition of
BT_ChatServer::NewMessage()'; /usr/bin/ld: DWARF error: invalid or unhandled FORM value: 0x23
chatserver_BT_copy.o:chatserver_BT_copy.cpp:(.text+0x2cf0): first defined here -
You must not reimplement a signal because it's done by moc but you did - either don't declare NewMessage() as signal or don't add an implementation for it.
-
You must not reimplement a signal because it's done by moc but you did - either don't declare NewMessage() as signal or don't add an implementation for it.
wrote on 11 Jan 2023, 20:01 last edited by Anonymous_Banned275 1 Nov 2023, 20:02@Christian-Ehrlicher Thanks, I just found that. It is a SIGNAL and not a function...
So I got it running but still no SLOT
Am I doing the "emit" correctly ?
connect(this,SIGNAL(NewMessage(QString text)), this,SLOT(PostMessage(QString text)));
// emit newMessage();
QString TESTtext = "TEST MESSAGE ";
emit NewMessage(TESTtext);
-
@Christian-Ehrlicher Thanks, I just found that. It is a SIGNAL and not a function...
So I got it running but still no SLOT
Am I doing the "emit" correctly ?
connect(this,SIGNAL(NewMessage(QString text)), this,SLOT(PostMessage(QString text)));
// emit newMessage();
QString TESTtext = "TEST MESSAGE ";
emit NewMessage(TESTtext);
wrote on 11 Jan 2023, 20:08 last edited by JoeCFD 1 Nov 2023, 20:09@AnneRanch
signals:
void NewMessage( const QString &msg);
private slots:
void PostMessage(const QString &msg );connect(this,SIGNAL(NewMessage(const QString &)),
this,SLOT(PostMessage(const QString &))); -
@Christian-Ehrlicher Thanks, I just found that. It is a SIGNAL and not a function...
So I got it running but still no SLOT
Am I doing the "emit" correctly ?
connect(this,SIGNAL(NewMessage(QString text)), this,SLOT(PostMessage(QString text)));
// emit newMessage();
QString TESTtext = "TEST MESSAGE ";
emit NewMessage(TESTtext);
Lifetime Qt Championwrote on 11 Jan 2023, 20:32 last edited by Chris Kawa 1 Nov 2023, 20:33@AnneRanch said:
Am I doing the "emit" correctly ?
No, you shouldn't pass argument names to these macros. Also these functions don't have any parameters in your first post, so there shouldn't be any in the connect. If you want to pass a string there you need to change function signatures too.
I know you said you don't want comments on the new syntax, but you really really really REALLY should use it. No, it's not a "lambda syntax". You don't have to use lambdas with it. It's just easier, safer, faster, has compile time errors and really should be your default. The old macro syntax is just legacy code at this point. You shouldn't be using it.
Modern syntax (you don't need to know anything about the parameters):
connect(this, &BT_ChatServer::NewMessage, this, &BT_ChatServer::PostMessage);
Old syntax (assuming you added parameters in these functions):
connect(this, SIGNAL(NewMessage(const QString &)), this, SLOT(PostMessage(const QString &)));
-
connect(this, &BT_ChatServer::NewMessage, this, &BT_ChatServer::PostMessage);
connect()
returns a boolean, so wrapping it withQ_ASSUME(connect(...))
will tell right away, if the connection was successful.
The syntax proposed by @Chris-Kawa is the recommended one. -
connect(this, &BT_ChatServer::NewMessage, this, &BT_ChatServer::PostMessage);
connect()
returns a boolean, so wrapping it withQ_ASSUME(connect(...))
will tell right away, if the connection was successful.
The syntax proposed by @Chris-Kawa is the recommended one.wrote on 11 Jan 2023, 21:15 last edited by@Axel-Spoerl Thanks , did not know connect return bool.
All solved , thanks everybody. -
@AnneRanch said in ":connect' error - "multiple definition..." ?:
@Axel-Spoerl Thanks , did not know connect return bool.
Well, the return type is actually
QMetaObject::Connection
, serving a boolean purpose in Q_ASSUME(). But I am sure you already knew, because you havertfQm
;-) -
wrote on 11 Jan 2023, 23:25 last edited by
I need to reopen this.
I am happy to post / connect local SIGNAL to local SLOT. but I cannot get to post to "remote" class.
In my case BT_SPP_CA_MainWindow.connect(this,&BT_ChatServer::NewMessage,BT_SPP_CA_MainWindow,&BT_SPP_CA_MainWindow::PostMessage);
but I am getting this s error and I do not understand what "value" is it asking for.
/mnt/07b7c3f8-0efb-45ab-8df8-2a468771de1f/PROJECTS/BT_JAN11_ V1/CCC_SOURCE/BLUETOOTH_LIBRARY/chatserver_BT_copy.cpp:35: error: 'BT_SPP_CA_MainWindow' does not refer to a value
chatserver_BT_copy.cpp:35:49: error: 'BT_SPP_CA_MainWindow' does not refer to a value
connect(this,&BT_ChatServer::NewMessage,BT_SPP_CA_MainWindow,&BT_SPP_CA_MainWindow::PostMessage);
^
./../BT_SPP_CA/bt_spp_ca_mainwindow.h:32:7: note: declared here
class BT_SPP_CA_MainWindow : public QMainWindow
^ -
I need to reopen this.
I am happy to post / connect local SIGNAL to local SLOT. but I cannot get to post to "remote" class.
In my case BT_SPP_CA_MainWindow.connect(this,&BT_ChatServer::NewMessage,BT_SPP_CA_MainWindow,&BT_SPP_CA_MainWindow::PostMessage);
but I am getting this s error and I do not understand what "value" is it asking for.
/mnt/07b7c3f8-0efb-45ab-8df8-2a468771de1f/PROJECTS/BT_JAN11_ V1/CCC_SOURCE/BLUETOOTH_LIBRARY/chatserver_BT_copy.cpp:35: error: 'BT_SPP_CA_MainWindow' does not refer to a value
chatserver_BT_copy.cpp:35:49: error: 'BT_SPP_CA_MainWindow' does not refer to a value
connect(this,&BT_ChatServer::NewMessage,BT_SPP_CA_MainWindow,&BT_SPP_CA_MainWindow::PostMessage);
^
./../BT_SPP_CA/bt_spp_ca_mainwindow.h:32:7: note: declared here
class BT_SPP_CA_MainWindow : public QMainWindow
^@AnneRanch said:
but I cannot get to post to "remote" class.
connect(this,&BT_ChatServer::NewMessage,BT_SPP_CA_MainWindow,&BT_SPP_CA_MainWindow::PostMessage);Connections are made between instances, not between classes. First and third parameters of connect should be pointers to source and destination instances.
this
is a pointer to instance of the class you're calling that code from. You've given a class name as the third parameter. You need to provide a pointer to the instance of that class instead. -
@AnneRanch said:
but I cannot get to post to "remote" class.
connect(this,&BT_ChatServer::NewMessage,BT_SPP_CA_MainWindow,&BT_SPP_CA_MainWindow::PostMessage);Connections are made between instances, not between classes. First and third parameters of connect should be pointers to source and destination instances.
this
is a pointer to instance of the class you're calling that code from. You've given a class name as the third parameter. You need to provide a pointer to the instance of that class instead.wrote on 12 Jan 2023, 01:06 last edited by@Chris-Kawa So I am reading it wrong , again
this (pointer) - source - is referring to a class which generates the SIGNAL
such class is called from the "parent" class which contains the desired destination SLOT
so I already have an instance of the destination and the source is in it.
If I create another class instance (pointer for the "destination class " - that is NOT where I want to send the message to.
I am actually looking n at this as a "parent / child" setting - I want to send a message generated by the child "up stream " to the parent..
-
@Chris-Kawa So I am reading it wrong , again
this (pointer) - source - is referring to a class which generates the SIGNAL
such class is called from the "parent" class which contains the desired destination SLOT
so I already have an instance of the destination and the source is in it.
If I create another class instance (pointer for the "destination class " - that is NOT where I want to send the message to.
I am actually looking n at this as a "parent / child" setting - I want to send a message generated by the child "up stream " to the parent..
Lifetime Qt Championwrote on 12 Jan 2023, 01:46 last edited by Chris Kawa 1 Dec 2023, 02:10this (pointer) - source - is referring to a class which generates the SIGNAL
No, not class. An instance of a class. An instance generates a signal. Class is just a type.
such class is called from the "parent" class which contains the desired destination SLOT
Classes are types. Types are not called. You can call o slot of an instance of a class.
If I create another class instance (pointer for the "destination class " - that is NOT where I want to send the message to.
Correct. Don't make a new instance. Get a pointer to the exact instance you want to send the signal to.
I am actually looking n at this as a "parent / child" setting
In general it doesn't have anything to do with parents/children. Connections are between instances of some classes. Those classes or instances don't have to be related in any way. The fact that in your case one of them is parent of the other is just anecdotal. It doesn't have special meaning for the connection.
I want to send a message generated by the child "up stream " to the parent
Although you technically can do that it's a bad design. Your operations should always be downstream, not up. Children are not supposed to know anything about their parents. This creates problems like yours - how do I get a pointer to parent. The answer is you shouldn't. It's the parent that should connect to its child's signal, because that's where you have the right context - pointers to both parent and child. When you're in the child's code you don't have easy access to the pointer to parent. Yes, you can call stuff like parentWidget() on
this
to get the parent and cast it to the right type, but that's ugly and hacky. The child gains knowledge about parent which it shouldn't have and you'll get into circular include problems fast.I'd say move your connection to the parent class.
this
wil point to your parent class instance and you'll have a pointer to the child there, so you can do a connection likeconnect(pointer_to_the_child, &BT_ChatServer::NewMessage, this, &BT_SPP_CA_MainWindow::PostMessage);
-
this (pointer) - source - is referring to a class which generates the SIGNAL
No, not class. An instance of a class. An instance generates a signal. Class is just a type.
such class is called from the "parent" class which contains the desired destination SLOT
Classes are types. Types are not called. You can call o slot of an instance of a class.
If I create another class instance (pointer for the "destination class " - that is NOT where I want to send the message to.
Correct. Don't make a new instance. Get a pointer to the exact instance you want to send the signal to.
I am actually looking n at this as a "parent / child" setting
In general it doesn't have anything to do with parents/children. Connections are between instances of some classes. Those classes or instances don't have to be related in any way. The fact that in your case one of them is parent of the other is just anecdotal. It doesn't have special meaning for the connection.
I want to send a message generated by the child "up stream " to the parent
Although you technically can do that it's a bad design. Your operations should always be downstream, not up. Children are not supposed to know anything about their parents. This creates problems like yours - how do I get a pointer to parent. The answer is you shouldn't. It's the parent that should connect to its child's signal, because that's where you have the right context - pointers to both parent and child. When you're in the child's code you don't have easy access to the pointer to parent. Yes, you can call stuff like parentWidget() on
this
to get the parent and cast it to the right type, but that's ugly and hacky. The child gains knowledge about parent which it shouldn't have and you'll get into circular include problems fast.I'd say move your connection to the parent class.
this
wil point to your parent class instance and you'll have a pointer to the child there, so you can do a connection likeconnect(pointer_to_the_child, &BT_ChatServer::NewMessage, this, &BT_SPP_CA_MainWindow::PostMessage);
wrote on 12 Jan 2023, 03:33 last edited by@Chris-Kawa So I moved the "connect" to "parent" .... Left the emit and the old test "connect" within "child".
The old test stuff still "passes the test message within child", the new connect does not.I am not sure if the "emit" which is in the child get "pickled up" by the "connect" in the "parent"...
I do agree with your comments about the software should be "from top down" , however the hardware runs just the opposite - from child to parent ....from down to up
I actually tried to use inheritance and got stuck with same issue - how to pass messages upstream.
However, after last few days I feel more confident I could try inheritance again.....
I am going to take few days off - saying final goodbye to old friend ... not sure if we are going to fly or drive west from Houston...
cheers
-
@Chris-Kawa So I moved the "connect" to "parent" .... Left the emit and the old test "connect" within "child".
The old test stuff still "passes the test message within child", the new connect does not.I am not sure if the "emit" which is in the child get "pickled up" by the "connect" in the "parent"...
I do agree with your comments about the software should be "from top down" , however the hardware runs just the opposite - from child to parent ....from down to up
I actually tried to use inheritance and got stuck with same issue - how to pass messages upstream.
However, after last few days I feel more confident I could try inheritance again.....
I am going to take few days off - saying final goodbye to old friend ... not sure if we are going to fly or drive west from Houston...
cheers
Lifetime Qt Championwrote on 12 Jan 2023, 12:09 last edited by Chris Kawa 1 Dec 2023, 12:19@AnneRanch said:
So I moved the "connect" to "parent" .... Left the emit and the old test "connect" within "child".
emit
should be in the object that signals the change, so yes, it should stay in the child, as that is where the change takes place.
connect
should be either where the slot is or somewhere outside entirely. For a parent/child connection it should be in the parent. For a connect ofthis
tothis
it should be in that class, not in the parent, so what you did sounds right.The old test stuff still "passes the test message within child", the new connect does not.
The type of connect doesn't matter. If it stopped working you just made something wrong.
however the hardware runs just the opposite - from child to parent
No, it doesn't. Hardware just does stuff. Child monitors the hardware and signals change in state. Parent picks up the signal and does something as a reaction. The information does flow upwards but the object structure is top to bottom.
I actually tried to use inheritance and got stuck with same issue - how to pass messages upstream.
It really doesn't sound like a job for inheritance. Inheritance represents "is" relation between classes. A dog is an animal. A car is a vehicle. Those are examples suited for inheritance. A dog has a collar. A car has a steering wheel. The "has" relation should be expressed as composition, not inheritance i.e. a parent has a child. In your case there is a MainWindow that has a ChatServer. That sounds like composition. MainWindow should not be a chat server.
-
@AnneRanch said:
So I moved the "connect" to "parent" .... Left the emit and the old test "connect" within "child".
emit
should be in the object that signals the change, so yes, it should stay in the child, as that is where the change takes place.
connect
should be either where the slot is or somewhere outside entirely. For a parent/child connection it should be in the parent. For a connect ofthis
tothis
it should be in that class, not in the parent, so what you did sounds right.The old test stuff still "passes the test message within child", the new connect does not.
The type of connect doesn't matter. If it stopped working you just made something wrong.
however the hardware runs just the opposite - from child to parent
No, it doesn't. Hardware just does stuff. Child monitors the hardware and signals change in state. Parent picks up the signal and does something as a reaction. The information does flow upwards but the object structure is top to bottom.
I actually tried to use inheritance and got stuck with same issue - how to pass messages upstream.
It really doesn't sound like a job for inheritance. Inheritance represents "is" relation between classes. A dog is an animal. A car is a vehicle. Those are examples suited for inheritance. A dog has a collar. A car has a steering wheel. The "has" relation should be expressed as composition, not inheritance i.e. a parent has a child. In your case there is a MainWindow that has a ChatServer. That sounds like composition. MainWindow should not be a chat server.
wrote on 12 Jan 2023, 20:19 last edited by@Chris-Kawa I am stuck....
Here are my two test macros
Q_ASSUME(connect(this, &BT_SPP_CA_MainWindow::NewMessage, this, &BT_SPP_CA_MainWindow::PostMessage)); Q_ASSUME(connect(server,&BT_ChatServer::NewMessage,this,&BT_SPP_CA_MainWindow::PostMessage));
The top one works when I "emit" NewMessage in BT_SPP_CA_MainWindow instance.
The bottom one does not work - it seems to ignore the "emit New Meassage" in BT_ChatServer and I have several of them which works fine "locally" in BT_ChatServer .
My "server" is initialized and processes other calls...including local emit NewMessage...
What else can I do to identify / debug the issue ?
-
@Chris-Kawa I am stuck....
Here are my two test macros
Q_ASSUME(connect(this, &BT_SPP_CA_MainWindow::NewMessage, this, &BT_SPP_CA_MainWindow::PostMessage)); Q_ASSUME(connect(server,&BT_ChatServer::NewMessage,this,&BT_SPP_CA_MainWindow::PostMessage));
The top one works when I "emit" NewMessage in BT_SPP_CA_MainWindow instance.
The bottom one does not work - it seems to ignore the "emit New Meassage" in BT_ChatServer and I have several of them which works fine "locally" in BT_ChatServer .
My "server" is initialized and processes other calls...including local emit NewMessage...
What else can I do to identify / debug the issue ?
@AnneRanch Are you sure you're connecting the right instances? You can print out the pointer and compare the addresses i.e.
qDebug() << server;
where you make that connection andqDebug() << this;
inside BT_ChatServer where you say it works. It should be the same address printed out. If not then you mixed your instances somewhere. -
@AnneRanch Are you sure you're connecting the right instances? You can print out the pointer and compare the addresses i.e.
qDebug() << server;
where you make that connection andqDebug() << this;
inside BT_ChatServer where you say it works. It should be the same address printed out. If not then you mixed your instances somewhere.wrote on 13 Jan 2023, 03:11 last edited by@Chris-Kawa Here is a snippet of app output
The pointers matchvoid BT_SPP_CA_MainWindow::Connect_MainServer()
BT_ChatServer::BT_ChatServer(QObject *)
"\n\t TASK Run \nBT_ChatServer::BT_ChatServer(QObject *)\n"
!!!!!!!!!!!!!!!!!!! this BT_ChatServer(0x5653f9b74550)
conncet OK
TASK Construct BT_ChatServer
BT_ChatServer::BT_ChatServer(QObject *)
& line "84"
!!!!!!!!!!!!!!!!!!!!server BT_ChatServer(0x5653f9b74550)
!!!!!!!!!!!!!!!!!!! this BT_ChatServer(0x5653f9b74550)
"emit NewMessage(text)"
void BT_ChatServer::PostMessage(const QString)
"\n\t TASK Run \nvoid BT_ChatServer::PostMessage(const QString)\n !!!! REMOTE !!!! TEST MESSAGE " -
@Chris-Kawa Here is a snippet of app output
The pointers matchvoid BT_SPP_CA_MainWindow::Connect_MainServer()
BT_ChatServer::BT_ChatServer(QObject *)
"\n\t TASK Run \nBT_ChatServer::BT_ChatServer(QObject *)\n"
!!!!!!!!!!!!!!!!!!! this BT_ChatServer(0x5653f9b74550)
conncet OK
TASK Construct BT_ChatServer
BT_ChatServer::BT_ChatServer(QObject *)
& line "84"
!!!!!!!!!!!!!!!!!!!!server BT_ChatServer(0x5653f9b74550)
!!!!!!!!!!!!!!!!!!! this BT_ChatServer(0x5653f9b74550)
"emit NewMessage(text)"
void BT_ChatServer::PostMessage(const QString)
"\n\t TASK Run \nvoid BT_ChatServer::PostMessage(const QString)\n !!!! REMOTE !!!! TEST MESSAGE "@AnneRanch It's very difficult for me to decipher that stream of random text without the matching code, but you said earlier that you had this:
Q_ASSUME(connect(server,&BT_ChatServer::NewMessage,this,&BT_SPP_CA_MainWindow::PostMessage));
but the output says this:
!!!!!!!!!!!!!!!!!!!!server BT_ChatServer(0x5653f9b74550) !!!!!!!!!!!!!!!!!!! this BT_ChatServer(0x5653f9b74550)
so which is it, because it's physically impossible that this output matches that connect.
this
can't be bothBT_SPP_CA_MainWindow
andBT_ChatServer
at the same time, so what's the real code that produces this output?. -
connect(this, &BT_ChatServer::NewMessage, this, &BT_ChatServer::PostMessage);
connect()
returns a boolean, so wrapping it withQ_ASSUME(connect(...))
will tell right away, if the connection was successful.
The syntax proposed by @Chris-Kawa is the recommended one.wrote on 13 Jan 2023, 08:16 last edited by@Axel-Spoerl said in ":connect' error - "multiple definition..." ?:
so wrapping it with Q_ASSUME(connect(...))will tell right away, if the connection was successful.
Will it, though? I had to quickly look up Q_ASSUME. From my understanding it just tells the compiler that you assert that the return value of the connect is always true. The compiler is allowed to use this assumption for optimization. If the assumption is wrong you have undefined behavior. Or does it actually do a check? I have seen people suggest Q_ASSERT, but this will only do the connect in the debug build, not in the release build. Is there a macro you could actually use here? Or am I mistaken about Q_ASSUME?
With the new connect syntax rarely if ever will the connect fail if it compiles. I have to admit that I never check the return value. Qt will write out warning to the console, though, when the connect fails. This is how you can figure this out at runtime as well.
-
@Axel-Spoerl said in ":connect' error - "multiple definition..." ?:
so wrapping it with Q_ASSUME(connect(...))will tell right away, if the connection was successful.
Will it, though? I had to quickly look up Q_ASSUME. From my understanding it just tells the compiler that you assert that the return value of the connect is always true. The compiler is allowed to use this assumption for optimization. If the assumption is wrong you have undefined behavior. Or does it actually do a check? I have seen people suggest Q_ASSERT, but this will only do the connect in the debug build, not in the release build. Is there a macro you could actually use here? Or am I mistaken about Q_ASSUME?
With the new connect syntax rarely if ever will the connect fail if it compiles. I have to admit that I never check the return value. Qt will write out warning to the console, though, when the connect fails. This is how you can figure this out at runtime as well.
wrote on 13 Jan 2023, 13:40 last edited by@SimonSchroeder said in ":connect' error - "multiple definition..." ?:
If the assumption is wrong you have undefined behavior. Or does it actually do a check?
I believe you are quite correct here. It does not do a check, unlike
Q_ASSERT
, rather it tells the compiler what is going to happen.The OP actually asked about this in Usage of Q_ASSUME in connect ?.
1/25