情景描述:

在qt的mainwindow.cpp下想使用udpthread.cpp下的函数,遇到定义的错误。

初始代码:

// mainwindow.cpp
直接使用BLEndianUint32
// udpthread.cpp
unsigned int BLEndianUint32(unsigned int value) {
return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24);
}

出现

error: use of undeclared identifier ‘BLEndianUint32’问题


解决方法1:类的定义

// udpthread.h
class udpThread : public QObject {
public:
unsigned int BLEndianUint32(unsigned int value);

// udpthread.cpp
unsigned int udpThread::BLEndianUint32(unsigned int value) {
return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24);
}

// mainwindow.h
udpThread *MyUdp;
// mainwindow.cpp
MyUdp = new udpThread;
value = MyUdp->BLEndianUint32(value);

BLEndianUint32函数写成udpthread类的公有成员

而在mainwindow中实例化一个对象MyUdp,再调用函数BLEndianUint32。

或者在类中直接定义也可以。

// udpthread.h
class udpThread : public QObject {
public:
unsigned int BLEndianUint32(unsigned int value) {
return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24);

或者把成员函数声明成静态函数

// udpthread.h
class udpThread : public QObject {
public:
static unsigned int BLEndianUint32(unsigned int value) {
return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24);

// mainwindow.cpp
value = MyUdp->BLEndianUint32(value); // 1
value = udpThread::BLEndianUint32(value); // 2

来源于 https://blog.csdn.net/weixin_43222324/article/details/99707095

下面我们来分析一下为什么可以这样改

(1)为什么要实例化

   仍然以上面的类Student为例。类Student表示学生,这是一个抽象的概念,表示的是所有学生。实例化一个对象Student XiaoWang;,这个对象表示的是具体的学生小王,你还可以实例化别的对象比如小张、小刘、小李、小周、小赵等等,这些对象都是具体的某个学生。

   类的成员函数getAge()的意思是得到学生的年龄,我们最直观的理解就是,学生的年龄那肯定是某一个具体的学生的年龄,如果你用Student.getAge()的方法调用年龄函数,那究竟得到的是哪个学生的年龄呢?所以对于这种非静态成员函数,我们要实例化一个对象比如学生小王,我们调用XiaoWang.getAge()得到的就是小王的年龄。

(2)为什么调用静态函数不需要实例化

   仍然以上面的类Student为例。如果现在我们要得到所有学生的平均年龄该怎么办呢?假如现在类Student里增加了一个函数getAverageAge(),我们想得到所有学生的平均年龄,难道还要先实例化一个对象表示具体的学生,再通过这个对象得到平均年龄吗?

   所有学生的平均年龄,是学生类Student的一个共同特点,我们可以把得到平均年龄函数声明成静态函数,static int getAverageAge();,然后无需实例化对象,直接通过Student::getAverageAge();的方式调用。

   类的静态函数表示的是这个类的一个共同特点,静态函数是类的所有对象所共享的,不是某一个对象特有的,就像平均年龄是所有学生所共有的而不是某个学生所特有的,因此,静态函数不需要实例化对象,直接通过类名::函数名的方式就能调用。

因此,在选择用上面两种方法中的哪一种方法的时候,需要根据你写的函数的意义。

(1)如果你写的函数表示的是对象特有的特性,比如学生的年龄函数,用第一种方法,实例化对象再调用函数,更好。
(2)如果你写的函数表示的是这个类的所有对象共享的特性,比如所有学生的平均年龄函数,用第二种方法,将该函数声明成静态函数,更好。
当然用哪种方法都可以,只是说用对场景更好。


解决方法2:内联函数

内联的目的就是在编译期让编译器把使用函数的地方直接替换掉,而不是像普通函数一样通过链接器把地址链接上。这种情况,如果定义没有在头文件的话,编译器是无法进行函数替换的。所以C++规定,内联函数可以在程序中定义多次,只要内联函数定义在同一个cpp中只出现一次就行。

来源于:https://jiadebin.github.io/2017/04/03/%E5%A4%B4%E6%96%87%E4%BB%B6%E4%B8%AD%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0%E5%BC%95%E5%8F%91%E7%9A%84multiple-definition/

// udpthread.h
inline unsigned int BLEndianUint32(unsigned int value) {
return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24);
}

然后在外就可以随意用BLEndianUint32了。


解决方法3:extern基础函数?

// udpthread.h
extern int BLEndianUint32(unsigned int value) ;
extern int BLEndianUint16(unsigned int value) ;
// mainwindow.cpp
extern int BLEndianUint32(unsigned int value);
extern int BLEndianUint16(unsigned int value);

// mainwindow.cpp
int BLEndianUint32(unsigned int value) {
return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) |
((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24);
}
int BLEndianUint16(unsigned int value) {
return ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
}