为了优化基于 Qt 的动态库的二进制文件,我尝试有选择地从继承自 QObject
的类中导出一些相关方法和使用moc
来定义自定义信号和槽,而不是完全导出它们(它们的所有成员)。下面是一些示例代码。
#ifdef LIB_BUILD
#define LIB_SHARED Q_DECL_EXPORT
#else
#define LIB_SHARED Q_DECL_IMPORT
#endif
class C: public QObject {
Q_OBJECT
public:
LIB_SHARED void f();
/* ... */
public slots:
LIB_SHARED void g();
private:
void h();
private slots:
void i();
};
想法:由于 h()
和 i()
是私有(private)的(并且没有内联方法调用任何这些函数),因此不需要导出这些符号,因为它们将单独由库使用。另一方面,f()
和 g()
是有资格导出的成员,因此它们被显式标记。
问题:Q_OBJECT
宏为 QObject
中的方法声明了几个虚拟方法重写,而这些方法不是 导出(因为宏将扩展为不包含LIB_SHARED
或Q_DECL_EXPORT
的声明)。因此,客户端代码中的虚拟表将是不完整的。
(不)解决方案:将LIB_SHARED
应用于整个类,正如通常建议的那样:
class LIB_SHARED C: public QObject { /* ... */ };
这解决了链接问题,但尚未达到主要目标(消除不必要的导出表条目),至少对于基于 QObject 的类而言是如此。
问题:有什么办法可以达到预期的结果吗?我尝试对 Q_OBJECT
宏进行一些修改,但没有成功。
我希望有一个也适用于 Linux 系统的解决方案(假设隐藏符号可见性为默认),因此 .def
文件不适用。不过,欢迎黑客入侵:)
感谢任何帮助。
PS:请注意,除了这个问题是在 Qt 环境中出现之外,它还可能发生在使用宏扩展来生成声明的任何地方,如本例所示。
最佳答案
尝试使用 pimpl idiom 并仅导出公共(public)部分。例如:
class CPrivate;
class LIB_SHARED C: public QObject {
Q_OBJECT
private:
CPrivate* m_private;
public:
...
};
并创建私有(private)类,放置所有私有(private)(不可导出)的东西:
class CPrivate : public QObject {
Q_OBJECT
public:
void h();
public slots:
void i();
}
然后初始化并从公共(public)类调用私有(private)实现。
关于c++ - 在基于 Qt 的库中选择性导出类成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9332996/