In an effort to optimize the binary of a Qt-based dynamic library, I'm attempting to selectively export a number of relevant methods from classes that inherit from QObject and use moc to define custom signals and slots, instead of exporting them entirely (all of their members). Some sample code is below.
#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();
};
The idea: since h() and i() are private (and no inline method call any of these functions), there is no need to export these symbols, since they will be used by the library alone. On the other hand, f() and g() are members eligible for exporting, so they're explicitly marked for that.
The problem: the Q_OBJECT macro declares a couple of virtual method overrides for methods in QObject, and these methods are not exported (since the macro will expand to declarations not containing LIB_SHARED or Q_DECL_EXPORT). Thus, the virtual table will be incomplete in client code.
The (un)solution: apply LIB_SHARED to the entire class, as it is typically suggested:
class LIB_SHARED C: public QObject { /* ... */ };
This solves linking problems, but the primary goal (eliminating unnecessary export table entries) is not reached, at least not for QObject-based classes.
The question: is there any way to achieve the desired result? I've tried messing a bit around the Q_OBJECT macro, with no success.
I hope for a solution that works on Linux systems too (assuming hidden symbol visibility as default), so .def files are not applicable. Hacks, however, are welcome :)
Any help is appreciated.
PS: Note that besides this problem is framed in a Qt environment, it can happen anywhere where a macro expansion is used to generate declarations, as in this case.
Try to use pimpl idiom and export only public part. For example:
class CPrivate;
class LIB_SHARED C: public QObject {
Q_OBJECT
private:
CPrivate* m_private;
public:
...
};
And create private class where placed all private (non exportable) stuff:
class CPrivate : public QObject {
Q_OBJECT
public:
void h();
public slots:
void i();
}
Then initialize and call private implementation from public class.
Related
I'm working on my first non-trivial project using the Qt Framework and to help maintain consistency across documents and to ensure I don't forget some small requirement I've decided to make a template document demonstrating the member functions, macros, etc. needed to subclass QObject. I also want to be able to fully utilize the Meta Object system. Am I missing anything or misunderstanding anything? Also feel free to give any general C++ critiques as necessary.
I'm especially concerned with the issue of whether or not to include a copy constructor. Is that only necessary for classes not derived from QObject?
Requirements (links are to the document I got the requirements from)
Public Default Constructor (link)
Public Copy Constructor (see 1) (but conflicts with this)
Public Destructor (see 1)
Use the Q_OBJECT Macro (link)
Ensure Properties Are Accessible with the Q_PROPERTY(...) Macro (link)
Declare the Type with Q_DECLARE_METATYPE(T) in the Header (link) (link)
Declare any Enums Used with Q_ENUM(E) in the Header (link)
Template Header
// Include guards
#ifndef CLASSNAME_H
#define CLASSNAME_H
// Include statements
#include <QObject>
#include <T.h>
// Enum definition
enum E{
E0,
E1,
E2
};
// Q_ENUM Macro
Q_ENUM(E)
// Class declaration
class ClassName : public QObject
{
// Q_OBJECT Macro
Q_OBJECT
// Q_PROPERTY Macros
Q_PROPERTY(T* memberA READ memberA WRITE setMemberA NOTIFY memberAChanged)
Q_PROPERTY(int memberB READ memberB WRITE setMemberB NOTIFY memberBChanged)
Q_PROPERTY(E memberC READ memberC WRITE setMemberC RESET resetMemberC)
public:
// Constructors and Destructor
ClassName(QObject *parent = nullptr);
ClassName() = default;
ClassName(const ClassName&) = default;
~ClassName();
// Getters
T* memberA() const {return m_memberA;}
int memberB() const {return m_memberB;}
E memberC() const {return m_memberC;}
// Setters
void setMemberA(T* newA);
void setMemberB(int newB);
void setMemberC(E newC);
signals:
void memberAChanged(T*);
void memberBChanged(int);
public slots:
void resetMemberC();
private slots:
private:
// Data Members
T* m_memberA;
int m_memberB;
E m_memberC;
};
// Meta Object Type Declaration
Q_DECLARE_METATYPE(TypeName);
// End include guard
#endif // CLASSNAME_H
The source file to accompany this header would likely be trivial, so I won't include it here. Though if anyone thinks it would be helpful to demonstrate some requirement or functionality, I'd be happy to write it out.
As Jeremy Friesner suggested, the requirements are not that strict. The situation is more like this:
If your class uses signals and/or slots, it must both have the Q_OBJECT macro and be derived from QObject,
If it only uses other meta-object functionality, such as Q_PROPERTY declarations, it can use the Q_GADGET macro and need not be derived from QObject,
If it doesn't need any of that, but should still be compatible with Qt templates like QVariant, it should be declared with Q_DECLARE_METATYPE. The same applies to enums and Q_ENUM.
A Q_PROPERTY/Q_INVOKABLE interface is only really needed if you need your class to be interoperable with QML code.
As for your other question, yes that is an important difference between QObjects and non-QObjects. The metatype must be copyable, which is why that is required of types you manually declare as metatypes, and also why the system instead uses pointers for QObject types, which are not copyable themselves. A minimal QObject declaration could start like this:
#ifndef CLASSNAME_H
#define CLASSNAME_H
#include <QObject>
// Enums in the global namespace cannot be registered; they must be enclosed
// in a class and registered with Q_ENUM, or in a namespace declared as
// Q_NAMESPACE and registered with Q_ENUM_NS
class ClassName : public QObject
{
Q_OBJECT
public:
// Default constructor, with explicit specifier to prevent accidental
// implicit conversion from a QObject*
explicit ClassName(QObject *parent = nullptr);
};
// ClassName* is automatically declared as a metatype
#endif // CLASSNAME_H
In general I'd recommend the "rule of zero": if possible, do not declare a destructor, nor any copy and move operations, and leave them to the compiler. Of course I also recommend all of the other guidelines there, if you have the time!
I have a bunch of base classes with defined Q_OBJECT macro and derived classes without it:
class Base : public QObject
{
Q_OBJECT
public:
// signals and slots
};
class Derived : public Base
{
// notice no `Q_OBJECT` macro
public:
// signals and slots
};
That works fine, but according to Qt docs:
The Q_OBJECT macro must appear in the private section of a class
definition that declares its own signals and slots or that uses other
services provided by Qt's meta-object system.
Is there any way to stop compilation when Q_OBJECT macro is absent for classes which use Qt meta-system?
PS: I'm using MSVC compiler
I've been lots of threads on this subject but I still miss the whole picture.
Suppose I have a program structure like this and I want to build the project as a shared library:
class Parent
{
public:
virtual double foo1() =0;
virtual double foo2() =0;
double foo3();
}
class Daughter1 : public Parent
{
public:
double foo1();
double foo2();
}
class Daughter2 : public Parent
{
public:
double foo1();
double foo2();
}
class evenmorecomplex:
{
public:
evenmorecomplex(const &Parent);
//
}
in lots of threads, I saw there is a declaration of
extern "C"
{
//functions for which I want to prevent the mangling
}
So my problem is double:
1) doesn't this method trash all the C++ object design?
2) obviously I can't declare two identical functions in the same scope...so, how can I export all the methods in this case?
Thanks everyone will make me things clearer.
[EDIT] Some more questions...just to understand better (sorry but I'm still a newbie in C++)...
3) if I had a non-virtual method (say foo3() ) in Parent, should I export also the Parent class, or the inherited (non-virtual) foo3 will be automatic "captured" while exporting Daughter1 and Daughter2? Should I selectively export that method in the Parent class?
4) suppose Parent is called in the constructor of another class (as reference)...since Parent can't be initialized the point is making the constructor to accept both Daughter1 and Daughter2. The question is: if I export only Daughter1 and Daughter2 (and evenmorecomplex) will this constructor still work?
This is compiler specific.
extern "C" is only useful when you want to export functions C style, if you want to export functions C style you won't be able to export functions with C++ calling conventions (such as any class functions)
On Windows / Visual-Studio, simply prefix your class with __declspec( dllexport ) when exporting or __declspec( dllimport ) when importing, like this:
class __declspec( dllexport ) MyClass{
float somefloat = 12.0f;
void fucn();
}
http://msdn.microsoft.com/en-us/library/81h27t8c.aspx
To use the same header, for both importing and exporting the class, you probably want to create a define/macro.
EDIT:
3&4, All base classes must be exportable, you can not inherit an exportable class from an non-exportable class. Its described in more detail here: http://msdn.microsoft.com/en-us/library/81h27t8c.aspx
Functions exported from an library outside of an "extern "C"" block like this are not callable from any language besides C++.
If you want to be able to call the functions from a different language, you either have to only export C functions, or export a COM interface.
Whilst reviewing some Qt C++ code I came across this:
class Foo
{
Q_OBJECT
signals:
virtual void someSignal(const QString& str, int n)
{
Q_UNUSED(str);
Q_UNUSED(n);
}
...
};
Now, Qt signals cannot have a body so I'm surprised this even compiles (perhaps because the body is effectively empty). I also don't see the point of making a signal virtual as ... it can't have a body so how can it be overridden?
Am I missing something here or is this a valid code smell?
That looks smelly to me.
It's valid to declare a signal in a base class and then emit it from a derived class, e.g.
class MyBase : public QObject
{
Q_OBJECT
// ...
signals:
void somethingHappened();
};
class MyDerived : public MyBase
{
Q_OBJECT
// ...
void doSomething();
};
void MyDerived::doSomething()
{
// ....
emit somethingHappened();
}
Maybe that's what the declaration in the question was meant to achieve.
Strictly C++ speaking it's normal it compiles, given signal is a macro for protected and Q_UNUSED is a cast to void.
But you should get an error when running moc which precisely creates the implementation of the methods declared as signals.
Qt signals are not allowed to be (pure) virtual. See comments to this bug - https://bugreports.qt.io/browse/QTBUG-41004
TL;DR: I don't know what the code was meant to do, but it's wrong (not merely smelling wrong, it's prima facie invalid). Signal implementations are always meant to be generated by moc. The body of the signal should be removed.
For the code to work, it should do all three: compile, get past moc, and link. It is true that your code does compile - the C++ compiler has no reason not to. But it won't pass through moc nor will it link.
Although perhaps moc didn't detect some of it back in 2010, here's how moc acts today:
a) moc doesn't allow signal definitions in class bodies, with the diagnostic Error: Not a signal declaration. So class X { Q_SIGNAL void s() {} }; triggers it, but class X { Q_SIGNAL void s(); }; void X::s() {} won't.
b) moc doesn't allow a Q_OBJECT macro in a class not deriving from QObject, with the diagnostic Error: Class contains Q_OBJECT macro but does not inherit from QObject.
Since it doesn't make any sense to talk about signals in classes that don't derive from QObject, let's assume that the code really looked as follows:
class Foo : public QObject
{
Q_OBJECT
signals:
virtual void someSignal(const QString&, int);
};
void Foo::someSignal(const QString& str, int n)
{
Q_UNUSED(str);
Q_UNUSED(n);
}
This will get past moc and will compile, but it won't link. The linker will issue a diagnostic for multiple declaration of Foo::someSignal. There's one definition in this file, and another in the moc-generated source.
I am making an abstract-base-class and was thinking I might want a pure virtual signal. But when I compiled I get a warning for the pure virtual signals I have defined:
../FILE1.h:27: Warning: Signals cannot be declared virtual
../FILE1.h:28: Warning: Signals cannot be declared virtual
Is it valid to define a pure virtual signal in C++/Qt? Is it valid to define a virtual signal?
Qt's signal and slot documentation page says you can define virtual slots but doesn't talk about signals. I can't seem to find good information on pure virtual signals.
Signals don't ever have an implementation[1] (i.e. you define the signal in your .h file and then there is no implementation in the .cpp).
The main purpose of declaring a function pure virtual is to force the inheriting class to provide an implementation.
Given the above two statements here's my thinking:
Signals don't have an implementation but declaring it pure virtual will require the inheriting class to provide an implementation... which directly conflict with "signals don't have an implementation". It's like asking someone to be in two places at once it's just not possible.
So in conclusion it seems like declaring a "pure virtual" "signal" should be an error and thus not valid.
In the case of an abstract base class here's what I think is correct:
When one declares the function only "virtual" it still gives the warning. To avoid any warnings I think the solution is to not qualify the signal with any "virtual" or "pure virtual" and then the inheriting class will not declare any signals but can still emit the signals defined in the base class.
[1] when I say that "signals don't ever have an implementation" I mean that the person implementing the class doesn't provide the implementation. I understand that behind the scene Qt's moc provides an implementation in the moc_FILE1.cpp .
The warning is reported by moc, not by the C++ compiler, and it is valid except in the specific case of abstract interfaces.
The only valid use for virtual signals is when declaring abstract interfaces that don't derive from QObject, as detailed in this excellent answer. There's nothing wrong with that approach. Moc tries to be helpful, since in most cases a virtual signal is a mistake.
Even then, the simple workaround for not getting the warning is to skip the signals: keyword in the interface. It is completely unnecessary, since the interface doesn't derive from QObject and thus shouldn't be processed by moc at all:
// https://github.com/KubaO/stackoverflown/tree/master/questions/virtual-slot-10029130
#include <QtCore>
class IDogInterface {
public:
// no signals: section since it's not a QObject!
virtual void barks() = 0; // a signal
};
class ADog : public QObject, public IDogInterface {
Q_OBJECT
public:
Q_SIGNAL void barks() override; // implementation is generated by moc
};
class Monitor : public QObject {
Q_OBJECT
int m_count{};
Q_SLOT void onBark() { m_count++; }
public:
int count() const { return m_count; }
void monitorBarks(IDogInterface * dog) {
QObject * dogObject = dynamic_cast<QObject*>(dog);
if (dogObject) {
connect(dogObject, SIGNAL(barks()), SLOT(onBark()));
} else {
qWarning() << "cannot monitor barking on dog instance" << (void*)dog;
}
}
};
int main() {
ADog dog;
Monitor monitor;
monitor.monitorBarks(&dog);
emit dog.barks();
Q_ASSERT(monitor.count() == 1);
}
#include "main.moc"
I think there's simply no point in having (pure) virtual signals. the signals macro provided to Qt simply expands to protected, so all the signals you're declaring are actually declarations of protected methods. The code generated by moc will provide the implementations of those functions.
there is a solution to create pure virtual function which will connect given slot to signal or vice versa. e.g.:
class IBaseInterface
{
public:
virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const = 0;
};
class CDerived : public QObject, public IBaseInterface
{
Q_OBJECT
public:
virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const;
signals:
void signal1(const QString& msg);
};
bool CDerived::connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const
{
if(bConnect)
return connect(this, SIGNAL(signal1(QString)), pReciever, pszSlot);
return disconnect(this, SIGNAL(signal1(QString)), pReciever, pszSlot);
}
further in clients code one may type:
class CSomeClass : public QObject
{
Q_OBJECT
protected /*or public, or private*/ slots:
void someSlot(const QString& msg);
};
void CSomeClass::somefunction()
{
IBaseInterface* p = new CDerived;
if (!p->connectToSignal1(this, SLOT(someSlot(QString)), true))
QMessageBox::warning(this, tr("Warning"), tr("Cannot connect ...."), QMessageBox::Ok);
}
Two scenarios where a virtual signal makes sense:
The derived class may want to selectively block the sending of a signal by skipping the base class implementation.
The derived class may want to use it as an event mechanism and react to the signal before or after sending it to listeners.
Both scenarios can also be handled in other less-OOP ways.