I have a base class that is inherited by two sub classes. All three classes use qDebug() to do some debug printing and Q_FUNC_INFO to identify the source of the print. The problem is that when printing from the base class, Q_FUNC_INFO contains the name of the base class, making it impossible to know which of the two sub classes the instance represents.
The best solution I have come up with so far is using a QString variable instead of Q_FUNC_INFO at the base class and supplying it with the correct name when instantiating.
Are there any other, more preferable solutions?
Are there any other, more preferable solutions?
In general, no, that is fine. In such cases, you would need to place the Q_FUNC_INFO into the subclass if that is possible. If not, you are out of luck, but... please read on.
Qt internally also uses explicit strings rather than Q_FUNC_INFO, I believe partially for this reason.
For QObjects, you could use the meta object compiler for some introspection to get the real name dynamically, namely:
const char * QMetaObject::className() const
Returns the class name.
and
const QMetaObject * QObject::metaObject() const [virtual]
Returns a pointer to the meta-object of this object.
A meta-object contains information about a class that inherits QObject, e.g. class name, superclass name, properties, signals and slots. Every QObject subclass that contains the Q_OBJECT macro will have a meta-object.
The meta-object information is required by the signal/slot connection mechanism and the property system. The inherits() function also makes use of the meta-object.
If you have no pointer to an actual object instance but still want to access the meta-object of a class, you can use staticMetaObject.
You also take a look into this when dealing with constructors as your comment seems to indicate it:
QMetaMethod QMetaObject::constructor(int index) const
Returns the meta-data for the constructor with the given index.
main.cpp
#include <QObject>
#include <QDebug>
class Foo : public QObject
{
Q_OBJECT
public:
virtual void baz() { qDebug() << "Class name:" << metaObject()->className(); }
};
class Bar : public Foo
{
Q_OBJECT
};
#include "main.moc"
int main()
{
Bar bar;
bar.baz();
return 0;
}
Output
moc main.cpp -o main.moc && g++ -Wall -I/usr/include/qt -I/usr/include/ -I/usr/include/qt/QtCore -lQt5Core -fPIC main.cpp && ./a.out
Class name: Bar
Note: if you would like to get this mechanism work in the constructor, the simple answer is that you cannot. Nothing will really help you there. That is due to the fact how inheritance is handled in C++. First, the base class is constructed, and at that stage, the subclass is yet fully constructed (strictly speaking, not even the base), so you cannot really get more information about it without explicitly making sure with an additional argument to the base class constructor. But then, you would get a bloated API just for this simple thing. I would suggest in such a case to just put the print into the subclasses as opposed to the base classes.
Related
I am reading other people's code and see this:
class UAVItem:public QObject,public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
...
But I didn't see they are using any sort of plug-in in this program.
Therefore, can I just remove the line:
Q_INTERFACES(QGraphicsItem)
?
If you have a class Derived which inherits from a class Base, which in turn inherits from QObject, and both Derived and Base contain the Q_OBJECT macro, then qobject_cast can be used to safely cast from a pointer (or reference) to Base, to a pointer (or reference) to Derived, similar to dynamic_cast in standard C++ but without RTTI.
If Base does not inherit from QObject, then qobject_cast can still be used in this way, but only if Base has a corresponding Q_DECLARE_INTERFACE macro and Derived contains Q_INTERFACES(Base).
In your case, Q_INTERFACES(QGraphicsItem) being present in UAVItem means that qobject_cast can be used to cast from a pointer (or reference) to QGraphicsItem to a pointer (or reference) to UAVItem, despite QGraphicsItem not inheriting from QObject.
From reference doc,
class ToolInterface
{
public:
virtual QString toolName() const = 0;
};
Q_DECLARE_INTERFACE(ToolInterface, "in.forwardbias.tool/1.0");
// Hammer in hammer.h (our Hammer plugin)
#include "toolinterface.h"
class Hammer : public QObject, public ToolInterface
{
Q_OBJECT
Q_INTERFACES(ToolInterface)
public:
QString toolName() const { return "hammer"; }
};
Q_EXPORT_PLUGIN2(hammer, Hammer);
When moc runs on the hammer.h code, it inspects Q_INTERFACES. It
generates code for a function called qt_metacall - void
*Hammer::qt_metacast(const char *iname). This goal of this 'casting' function is to return a pointer to an interface depending on iname.
moc also verifies whether the interface names that you have put inside
Q_INTERFACES have indeed been declared. It can do this by inspecting
the header files and looking for a Q_DECLARE_INTERFACE. In our case,
there is a Q_DECLARE_INTERFACE inside toolinterface.h.
According to http://qt-project.org/doc/qt-4.8/moc.html#multiple-inheritance-requires-qobject-to-be-first the QObject must be the first in the base classes when using multiple inheritance.
Is this because of some limitation in the moc tool or C++ memory layout problems are taken into consideration too, thus this restriction came into existence?
Assume that we have a class Test declared as:
class Test : public Foo, public QObject
{
Q_OBJECT
[..]
};
If you take a look at the moc_test.cpp file that the moc tool has generated, you will see something like:
[..]
const QMetaObject Command::staticMetaObject = {
{ &Foo::staticMetaObject, qt_meta_stringdata_Command,
qt_meta_data_Command, &staticMetaObjectExtraData }
};
[..]
Compiler will complain about staticMetaObject not being the member of Foo, as Foo is not a QObject. For some reason the moc tool generates this code taking the first parent class. Thus if you declare Test as:
class Test : public QObject, public Foo {};
The generated code will look fine to compiler.
I think this is made just for convenience because moc tool will hardly know which of the parent classes is a QObject without parsing the whole hierarchy.
Note: If you don't use the Q_OBJECT macro, you can derive your class from others in any order.
Yesterday I was asked to recreate a regular QT form using QML (which was my first attempt ever using QLM). Everything was going well until I tried using c++ methods in the QML. This is obviously not the original code, but the scenario looks something like this:
I have a super class deriving from QObject, with some properties, methods and even virtual methods:
class SuperClass : public QObject {
Q_OBJECT
Q_PROPERTY(QString someProperty READ someProperty WRITE setSomeProperty)
protected:
QString m_someProperty;
public:
QString someProperty(void){return m_someProperty;} //get method
void setSomeProperty(QString newValue){m_someProperty = newValue;} //set method
Q_INVOKABLE virtual QString printSomething(void) = 0;
}
And then I have a class deriving from the SuperClass (like a specialization) with some more specific properties and methods and of course the virtual methods implementations and stuff:
class DerivedClass : public SuperClass {
Q_PROPERTY(QString someSpecificProperty READ someSpecificProperty WRITE setSomeSpecificProperty)
private:
QString m_someSpecificProperty;
public:
QString specificProperty(void){return m_someSpecificProperty;} //get method
void someSpecificProperty(QString newValue){m_someSpecificProperty = newValue;} //set method
QString printSomething(void){return QString("Something!");} //SuperClass virtual method
Q_INVOKABLE QString printSomethingSpecific(void){return QString("Something Specific!");}
}
OK, this is it! Now assuming that DerivedClass is instantiated and added to the QML context properly under the name of "DrvClass" for example and that I have some QML control like a TextField which has a 'text:' property:
text: DrvClass.someProperty
using MasterClass' properties, it works just fine.
text: DrvClass.printSomething()
even using virtual methods from MasterClass' which are implemented in the derived class works fine. but...
text: DrvClass.someSpecificProperty
doesn't work and I get something like "Unable to assign [undefined] to QString"
text: DrvClass.printSomethingSpecific()
also doesn't work! "TypeError: Property 'printSomethingSpecific' of object SuperClass() is not a function" And the weird part is that it says that it's not a function from the SuperClass, being the instantiated class the Derived one!
I've looked for similar errors, but most of the time is from people who just forgot to include the Q_OBJECT macro... Mine's there for sure!
It seems that QML doesn't like much classes deriving from other classes that derive from QObjects :-/ Probably something to do with the meta-object compiler who only looks for invokable methods where it finds the Q_OBJECT macro and not on it's subclasses!
So what you guys think the solution for this might be?
I could just add the Q_OBJECT macro to the DerivedClasses instead of the SuperClass, but I really need the SuperClass to be a QObject because of signals and stuff! So is there some other macro I have to add to the DerivedClass for the moc to 'see' it?
Or is this just the fruit of inexperience and I'm doing a dumb mistake somewhere?
DerivedClass is missing Q_OBJECT macro (it is not inherited!).
Then simply run qmake again on your project & compile: it should work.
I have created a base class that provides a common signal for all its subclasses:
#include <QWidget>
namespace Dino {
/**
* #brief Base class for all single-value settings editors
*
* Provides a valueChanged() signal that can be used to propagate changes to
* values up to the MainWindow
*/
class TypeEditor : public QWidget
{
Q_OBJECT
public:
explicit TypeEditor(QWidget *parent = 0):QWidget(parent){}
signals:
void valueChanged();
};
} // namespace Dino
In a subclass, I want to have this signal available, but also define a more specific signal with the same name but different arguments:
#include "ui/typeeditor.h"
namespace Dino {
class BoolEditor : public TypeEditor
{
Q_OBJECT
public:
explicit BoolEditor(QWidget* parent = 0):TypeEditor(parent){}
signals:
void valueChanged(bool value);
public slots:
void setValue(bool value)
{
emit valueChanged(value);
emit valueChanged();
}
};
} // namespace Dino
The idea is that when only the base class type is known, the generalized signal can be used, which tells that there has been a change in the value. When the exact subclass type is known, another signal is available, which tells the new value.
Now, when I try to compile I get an error on the emit valueChanged() stating that there is no function called Dino::BoolEditor::valueChanged().
When I rename the signal in the base class to something else it works, so this seems to be a problem of overloading the signal. I would be interested in the reason for this. Is it some design requirement that I'm not aware of that prevents me from overloading a signal in a subclass, or am I just missing something in the code?
Signal is just a protected function. You can't overload base class functions like that
See this question for more details
This is overloading methods in C++. Try:
emit TypeEditor::valueChanged();
it is a problem of overloading the signal.
First, your issue is a C++one, not a Qt one. Then in your case,you cannot speak of overloading.
If you define in derived class a method with same name and signature than a base class method,then you are overloading. If you had b->valueChanged(), with this signal with no parameters defined in base class, here you would get no compile error.
When compiling your code, compiler looks fot a valueChanged() signal in closest scope, that is scope of B class. He finds a valueChanged(bool) and then checks argument list. Since there is no match, there is compile error.
What you are doing is called "shadowing" or "hiding" a name. When the compiler does its magic to copy an inheritance hierarchy into a base class (I know that there is more to that, I'm just simplifying), it first looks in the current scope to see if there is something with the same name. If it can find a member with the same name (not the signature or type) as what you are looking for, it doesn't look any further, even if there are better candidates in the inheritance hierarchy!
So, how do you get around this? You can import the declaration from the parent class into the derived class with a using statement. (You can see more about this here.)
For example:
struct A {
int f() { return 42; }
};
struct B : A {
using A::f; // <- This is the magic line!
int f(int n) { return 42 + n; }
};
That using A::f; statement in the derived class adds the f member from A into the current scope and now both functions are visible and can be used!
Here is a runnable example on ideone.
is it possible to return exemplar of object using passed type name (string) in c++?
I have some base abstract class Base and a few derivates. Example code:
class Base
{
/* ... */
};
class Der1 : public Base
{
/* ... */
};
class Der2 : public Base
{
/* ... */
};
And I need function like:
Base *objectByType(const std::string &name);
Number of derivates classes are changeable and I don't want to make something like switching of name and returning by hands new object type. Is it possible in c++ to do that automatically anyway?
p.s. usage should looks like:
dynamic_cast<Der1>(objectByType("Der1"));
I need pure c++ code (crossplatform). Using boost is permissible.
There is a nice trick which allows you to write a factory method without a sequence of if...else if....
(note that, AFAIK, it is indeed not possible to do what you want in C++ as this code is generated in the compile time. A "Factory Method" Design Pattern exists for this purpose)
First, you define a global repository for your derived classes. It can be in the form std::map<std::string, Base*>, i.e. maps a name of the derived class to an instance of that class.
For each derived class you define a default constructor which adds an object of that class to the repository under class's name. You also define a static instance of the class:
// file: der1.h
#include "repository.h"
class Der1: public Base {
public:
Der1() { repository[std::string("Der1")] = this; }
};
// file: der1.cpp
static Der1 der1Initializer;
Constructors of static variables are run even before main(), so when your main starts you already have the repository initialized with instances of all derived classes.
Your factory method (e.g. Base::getObject(const std::string&)) needs to search the repository map for the class name. It then uses the clone() method of the object it finds to get a new object of the same type. You of course need to implement clone for each subclass.
The advantage of this approach is that when you are adding a new derived class your additions are restricted only to the file(s) implementing the new class. The repository and the factory code will not change. You will still need to recompile your program, of course.
It's not possible to do this in C++.
One options is to write a factory and switch on the name passed in, but I see you don't want to do that. C++ doesn't provide any real runtime reflection support beyond dynamic_cast, so this type of problem is tough to solve.
Yes that is possible! Check this very funny class called Activator
You can create everything by Type and string and can even give a List of parameters, so the method will call the appropriate constructor with the best set of arguments.
Unless I misunderstood, the typeid keyword should be a part of what you are looking for.
It is not possible. You have to write the objectByType function yourself:
Base* objectByType(const std::string& name) {
if (name == "Der1")
return new Der1;
else if (name == "Der2")
return new Der2;
// other possible tests
throw std::invalid_argument("Unknown type name " + name);
}
C++ doesn't support reflection.
In my opinion this is the single point where Java beats C++.
(ope not to get too many down votes for this...)
You could achieve something like that by using a custom preprocessor, similar to how MOC does for Qt.