Weird undefined error regarding object in a class when it has been defined...
-
So, I've read a lot about undefined errors, but I'm confused about my situation, and even a little worried since the error message isn't something "clean".
Here's my code. First, the .h file :
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtSerialPort/QSerialPort> #include <QSerialPortInfo> #include <QProgressDialog> #include <QProgressBar> #include <QThread> #include <QFile> #include <QFileDialog> #include <QLabel> #include <QString> #include <QIODevice> extern "C"{ #include "bootloader.h" } QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; }; class BootLoader { public: BootLoader(); ~BootLoader(); BOOTLOADERERROR err; BOOTLOADER b; UnionX addr; QString port; QSerialPortInfo portinfo; static QSerialPort BootSerial; }; #endif // MAINWINDOW_H
Now for the .cpp :
void boot_rst(unsigned char value) { BootLoader::BootSerial.setRequestToSend(value); } unsigned char write_uart(unsigned char data_byte_count, unsigned char* data_to_write) { return BootLoader::BootSerial.write((char*) data_to_write, data_byte_count); } unsigned char read_uart(unsigned char data_byte_count, unsigned char* data_read) { return BootLoader::BootSerial.read((char*) data_read, data_byte_count); } void wait(unsigned int micros) { QObject().thread()->usleep(micros); } BootLoader::BootLoader() { err = INIT_NOT_DONE; b.init_done = 0; b.boot_ready = 0; addr.address_l = 0; port = QString("COM3"); portinfo = QSerialPortInfo(port); //BootSerial = new QSerialPort(nullptr); BootLoader::BootSerial.QSerialPort::setPort(portinfo); BootLoader::BootSerial.setBaudRate(115200); BootLoader::BootSerial.setParity(QSerialPort::EvenParity); bootloaderInitQt(&b, boot_rst, write_uart, read_uart, wait); }
I omitted some stuff which isn't relevant to the part I'm looking at. Now for the error :
:-1: erreur : debug/mainwindow.o:mainwindow.cpp:(.rdata$.refptr._ZN10BootLoader10BootSerialE[.refptr._ZN10BootLoader10BootSerialE]+0x0): undefined reference to `BootLoader::BootSerial'
Could someone help point out what I'm doing wrong here ? The objective is to have those functions write_uart, read_uart etc serve as pointers to functions from the QSerialPort module. I have made a previous version of the bootloader (which works, and is in a .c file), so I'm fairly confident it isn't the cause of the problem. Any idea would be helpful.
Edit to add : I'm using the .c bootloader for compilation, which is where the BOOTLOADER and BOOTLOADERERROR types are defined (one is a structure, the other is an enum to point out what the error is during the program.)
Worth noting, I don't have a lot of experience in C++ ^^"
-
Finally figured it out ! I was on the right track, but I wasn't doing things "smart". I ended up making an instance of my BootLoader class in my MainWindow, so I could access the members. I had to put the BootLoader members on public, I had no choice here. But the instanciation made calling on the variables so much easier.
In short, I had only done half the work when I wrote my class, I had to actually use it somewhere.
Thanks for the answers ! And I'll be brushing up my C++ for future use.
Here's what the new code looks like, for reference :
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtSerialPort/QSerialPort> #include <QSerialPortInfo> #include <QProgressDialog> #include <QProgressBar> #include <QThread> #include <QFile> #include <QFileDialog> #include <QLabel> #include <QString> #include <QIODevice> extern "C"{ #include "bootloader.h" } QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class BootLoader { public: BootLoader(); ~BootLoader(); //private: BOOTLOADERERROR err; BOOTLOADER b; UnionX addr; QString port; QSerialPortInfo portinfo; QSerialPort BootSerial; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; QLabel *statusLabel; QLabel *sizeLabel; QProgressBar *statusProgressBar; QLabel *LabelGive; QLabel *LabelGet; QSerialPort *serial; QString port; QSerialPortInfo portinfo; BootLoader B; void boot_rst(unsigned char value); unsigned char write_uart(unsigned char data_byte_count, unsigned char* data_to_write); unsigned char read_uart(unsigned char data_byte_count, unsigned char* data_read); void wait(unsigned int micros); }; #endif // MAINWINDOW_H
And the .cpp :
void MainWindow::boot_rst(unsigned char value) { B.BootSerial.setRequestToSend(value); } unsigned char MainWindow::write_uart(unsigned char data_byte_count, unsigned char* data_to_write) { return B.BootSerial.write((char*) data_to_write, data_byte_count); } unsigned char MainWindow::read_uart(unsigned char data_byte_count, unsigned char* data_read) { return B.BootSerial.read((char*) data_read, data_byte_count); } void MainWindow::wait(unsigned int micros) { QObject().thread()->usleep(micros); } BootLoader::BootLoader() { err = INIT_NOT_DONE; b.init_done = 0; b.boot_ready = 0; addr.address_l = 0x08000000; port = QString("COM3"); portinfo = QSerialPortInfo(port); //BootSerial = new QSerialPort(nullptr); /*BootLoader::BootSerial.setPort(portinfo); BootLoader::BootSerial.setBaudRate(115200); BootLoader::BootSerial.setParity(QSerialPort::EvenParity); BootLoader::BootSerial.open(QIODeviceBase::ReadWrite); bootloaderInitQt(&b, boot_rst, write_uart, read_uart, wait);*/ this-> BootSerial.setPort(portinfo); BootSerial.setBaudRate(115200); BootSerial.setParity(QSerialPort::EvenParity); } unsigned char value = 0; MainWindow::~MainWindow() { delete ui; } BootLoader::~BootLoader() { }
-
hi, and welcome
first off, please use code tags for your code, those make reading them much easier :D its ``` in the beginning and the end of the code block
secondly:
static QSerialPort BootSerial;don't make stack allocated QObjects static! its not permitted and my lead to problems
3rdly:
BootLoader::BootSerial.QSerialPort::setPort(portinfo);
this os most definitely the wrong way to access the set port function of your serialport instance :Dclass BootLoader { public: BootLoader(); ~BootLoader(); private: BOOTLOADERERROR err; BOOTLOADER b; UnionX addr; QString port; QSerialPortInfo portinfo; QSerialPort BootSerial; };
BootLoader::BootLoader() { err = INIT_NOT_DONE; b.init_done = 0; b.boot_ready = 0; addr.address_l = 0; port = QString("COM3"); portinfo = QSerialPortInfo(port); //old and wrong //BootLoader::BootSerial.QSerialPort::setPort(portinfo); //BootLoader::BootSerial.setBaudRate(115200); //BootLoader::BootSerial.setParity(QSerialPort::EvenParity); this-> BootSerial.setPort(portinfo); // this can (in this case) be omitted in c++, the so following is also ok: BootSerial.setBaudRate(115200); BootSerial.setParty(QSerialPort::EvenParity); }
Worth noting, I don't have a lot of experience in C++ ^^"
I could tell :P
-
Thanks for the code block tip, makes a world of difference !
The reason I put the parameters as public in the BootLoader class is because I have an issue when setting the pointers to the functions I want. So now, this :
void boot_rst(unsigned char value) { BootLoader::BootSerial.setRequestToSend(value); }
returns the error : "BootSerial is a private member of BootLoader", hence why I thought putting them as public would help.
-
Tried a few more things before I realized I didn't remove the static before my BootSerial member. Now I just have "two" errors to solve, the fact that BootSerial is private or protected and can't be accessed, and the fact that it's a non-static member and I'm using it wrong. It's also something that is going to affect the UnionX member (which is a union between a long int and an array of four bytes for storing an address and rearranging the byte order), so now it's just a matter of what am I doing wrong here.
-
Finally figured it out ! I was on the right track, but I wasn't doing things "smart". I ended up making an instance of my BootLoader class in my MainWindow, so I could access the members. I had to put the BootLoader members on public, I had no choice here. But the instanciation made calling on the variables so much easier.
In short, I had only done half the work when I wrote my class, I had to actually use it somewhere.
Thanks for the answers ! And I'll be brushing up my C++ for future use.
Here's what the new code looks like, for reference :
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtSerialPort/QSerialPort> #include <QSerialPortInfo> #include <QProgressDialog> #include <QProgressBar> #include <QThread> #include <QFile> #include <QFileDialog> #include <QLabel> #include <QString> #include <QIODevice> extern "C"{ #include "bootloader.h" } QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class BootLoader { public: BootLoader(); ~BootLoader(); //private: BOOTLOADERERROR err; BOOTLOADER b; UnionX addr; QString port; QSerialPortInfo portinfo; QSerialPort BootSerial; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; QLabel *statusLabel; QLabel *sizeLabel; QProgressBar *statusProgressBar; QLabel *LabelGive; QLabel *LabelGet; QSerialPort *serial; QString port; QSerialPortInfo portinfo; BootLoader B; void boot_rst(unsigned char value); unsigned char write_uart(unsigned char data_byte_count, unsigned char* data_to_write); unsigned char read_uart(unsigned char data_byte_count, unsigned char* data_read); void wait(unsigned int micros); }; #endif // MAINWINDOW_H
And the .cpp :
void MainWindow::boot_rst(unsigned char value) { B.BootSerial.setRequestToSend(value); } unsigned char MainWindow::write_uart(unsigned char data_byte_count, unsigned char* data_to_write) { return B.BootSerial.write((char*) data_to_write, data_byte_count); } unsigned char MainWindow::read_uart(unsigned char data_byte_count, unsigned char* data_read) { return B.BootSerial.read((char*) data_read, data_byte_count); } void MainWindow::wait(unsigned int micros) { QObject().thread()->usleep(micros); } BootLoader::BootLoader() { err = INIT_NOT_DONE; b.init_done = 0; b.boot_ready = 0; addr.address_l = 0x08000000; port = QString("COM3"); portinfo = QSerialPortInfo(port); //BootSerial = new QSerialPort(nullptr); /*BootLoader::BootSerial.setPort(portinfo); BootLoader::BootSerial.setBaudRate(115200); BootLoader::BootSerial.setParity(QSerialPort::EvenParity); BootLoader::BootSerial.open(QIODeviceBase::ReadWrite); bootloaderInitQt(&b, boot_rst, write_uart, read_uart, wait);*/ this-> BootSerial.setPort(portinfo); BootSerial.setBaudRate(115200); BootSerial.setParity(QSerialPort::EvenParity); } unsigned char value = 0; MainWindow::~MainWindow() { delete ui; } BootLoader::~BootLoader() { }
-
Thanks for the code block tip, makes a world of difference !
The reason I put the parameters as public in the BootLoader class is because I have an issue when setting the pointers to the functions I want. So now, this :
void boot_rst(unsigned char value) { BootLoader::BootSerial.setRequestToSend(value); }
returns the error : "BootSerial is a private member of BootLoader", hence why I thought putting them as public would help.
@DexTr somehow you stopped reading after the class definition I gave. The most relevant part was just a little bit further down:
this-> BootSerial.setPort(portinfo); // this can (in this case) be omitted in c++, the so following is also ok: BootSerial.setBaudRate(115200); BootSerial.setParty(QSerialPort::EvenParity);
but, you got it working, and thats what matters!
-
@DexTr somehow you stopped reading after the class definition I gave. The most relevant part was just a little bit further down:
this-> BootSerial.setPort(portinfo); // this can (in this case) be omitted in c++, the so following is also ok: BootSerial.setBaudRate(115200); BootSerial.setParty(QSerialPort::EvenParity);
but, you got it working, and thats what matters!
@J-Hilk I did read that part and implemented it, but the issues were still there. It was more of a "I was using the class like my left foot" problem.
I got new errors but none warranting a continuation of that thread. Still, thank you for your time and patience !