Initialize uncopyable third-party base class, with pointer to object - c++

I'm fighting with Qt. Cannot find out reliable solution for my specific problem.
We have custom class MyWidget that must:
be derived from QWidget to override closeEvent method
have fields that must be initialzed in constructor
Problems:
QWidget's guts initialized with QUiLoader from .ui file. So I have only QWidget* pointer
QWidget is non-copyable.
QWidget has no move constructor
The code (error checking and memory management are omitted for simplicity):
class MyWidget : public QWidget
{
bool m_Closed;
public:
MyWidget(QWidget* qw) :
QWidget(*qw), // error: copy constructor is private
m_Closed(false)
{}
bool IsClosed() const { return m_Closed; }
virtual void closeEvent(QCloseEvent *) override { m_Closed = true; }
};
QFile file("main.ui");
QUiLoader uiLoader;
MyWidget* uiMain = new MyWidget(uiLoader.load(&file));
uiMain->show();
Questions:
How can I workaround this? I feel that solution is very simple.
Can I use move semantics here somehow?
Note that:
I cannot make QWidget member, as I need to override its method.
Probably, I can make some MyWidget::Init() method, to init those bool flag, which must be called after each instantiation. But I find this solution unreliable.
In the end, I must just have QWidget, that I can check if it was closed or not (maybe you know another, simple way)
I use MSVC 2013 RC and GCC 4.8.1, so C++11 solution would be great
Do not hesitate, I appreciate any suggestions and criticism.

.ui files can use custom classes that derive from QWidget, so you can use your class in the Designer - even without writing any Designer plugins (it won't be shown). Right-click on a widget and select "Promote".
You need to create your own derived version of QUiLoader, and provide an implementation of the factory method QUiLoader::createWidget that can create your widgets. See this answer for a complete example.
Then you put your initialization code in the derived widget.

Related

Compile time check that a class inherits from a base class and use as it

The title of the question is not very clear, I'll try to explain better.
I'm using Qt and the windows I'm working with derive (directly or indirectly) from QWidget. My windows has to be treat uniformly, so that I can take a pointer to the currently active window and invoke methods on it not knowing the actual window class, for this reason all my windows derive from another class, let's call it "myScreen". So far so good.
Now I would like to handle in "myScreen" also the hiding and showing of a window, so that it's uniform. For example passing from a window to another may imply calling "hide()" on the current window and "show()" on the new window. Since "myScreen" and QWidget don't have any relationship, I must use dynamic_cast to cast the windows that I know derive from "myScreen" and "QWidget" inside "myScreen" methods, in order to call the functions of QWidget just mentioned.
I know that probably the best way could be having "myScreen" derive from QWidget and all of other windows derive from that, but my goal is to change as little as possible the existing code. I also tried using virtual inheritance, but this approach can't work because of the files generated automatically by the moc (see this link Cannot convert from pointer to base class to pointer to derived class).
By now I managed to ensure that a constructor of "myScreen" is called by a class that derives from QWidget:
struct isQWidget{
class QWidgetType{
QWidgetType(){}
friend struct isQWidget;
};
template<class T>
static QWidgetType isQwidgetType(const T&){
static_assert (std::is_base_of<QWidget, T>::value, "Error: not a QWidget");
return QWidgetType();
}
};
Constructor declaration:
myScreen(myScreen& parentScreen, isQWidget::QWidgetType);
Constructor definition:
sigin::sigin(QWidget *parent, myScreen& si) :
QWidget(parent),
myScreen(si, isQWidget::isQwidgetType(*this)),
ui(new Ui::sigin)
{
ui->setupUi(this);
}
I would like to treat a pointer to myScreen as a pointer to QWidget inside "myScreen" compile-time, since I know I will always use something that derives from QWidget.
Any idea on how I can manage this problem?
I had something like this in mind
template <typename T>
myScreen::myScreen(T &parent)
{
static_assert(std::is_base_of<QWidget, T>::value, "Error: not a QWidget");
QWidget &parentQt = dynamic_cast<QWidget&>(parent); // guaranteed to succeed in runtime by the above
...
}
So for parent which does not inherit from QWidget that would be a compilation error, and which does would always cast successfully.

Can't access C++ QObject subclass methods from QML

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.

Copying classes derived from QGraphicsItem using memcpy does not creat new object

I have several different classes derived from QGraphicsItem or its children (like QGraphicsRectItem). I am at the point when I need to copy selected objects of those classes while not knowing exactly which one I copy.
Since QGraphicsScene::selectedItems() return a list of selected items I decided to use it, however I cannot copy the QGraphicsItem since its an abstract class. To address this I am trying to copy the object using malloc and memcpy.
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene();
item = new QGraphicsRectItem(50,50,50,50);
item->setFlag(QGraphicsItem::ItemIsSelectable);
scene->addItem(item);
item->setSelected(true);
ui->graphicsView->setScene(scene);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
for(QGraphicsItem *item : scene->selectedItems())
{
QGraphicsItem *copiedItem=(QGraphicsItem *)malloc(sizeof(*item));
memcpy(copiedItem, item, sizeof(*copiedItem));
copiedItem->moveBy(50, 50);
scene->addItem(copiedItem);
qDebug() << item;
qDebug() << copiedItem;
}
}
MainWindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QGraphicsScene *scene;
QGraphicsRectItem *item;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
GUI consisting of QGraphicsView and QPushButton is sufficient for this example.
This code seem to work, item and copiedItem have different addresses but the same properties as qDebug() returns.
The scene however return the following error:
QGraphicsScene::addItem: item has already been added to this scene
I don't quite understand why the scene thinks the items are the same while they have different addresses. Is there any way to solve this issue?
EDIT:
If possible I would like to do this without modifying the code of classes derived from QGraphicsItem, since this is a group work and I would not like to bug other functionalities.
If you look at the class definition inside qgraphicsitem.h, you'll see the following:
private:
Q_DISABLE_COPY(QGraphicsItem)
Q_DECLARE_PRIVATE(QGraphicsItem)
What this means is that, by design, you are not supposed to copy a QGraphicsItem, each object is supposed to be unique.
EDIT:
I would imagine that the reason that you are denied the copying ability is because QGraphicsItem follows the Composite Design Pattern. Creating a copy of a single object that has child items would result in child items having more than one parent. To get round that, you'd have to not only copy the item you're interested in but every child in the child hierarchy as well. For very large hierarchies, this can become a very time-consuming operation.
If you really feel that you need to make copies, you can create a cloning factory function/class that creates a clone of the QGraphicsItem and all it's children by going through all the object's properties and transferring them to a newly created QGraphicsItem.
If this is not feasible, perhaps think about accomplishing your goal in a different way.
You really want to be using the copy constructor or the assignment operator, not malloc and memcpy. This is how you copy objects in C++:
QGraphicsItem copiedItem = *item;
The problem of copying a class by block copying its memory with malloc is that if the class contains pointers to objects or arrays, then only a shallow copy will occur.
In your case of getting pointers to a QGraphicsItem, you'll need to identify the type of item you're copying (its actual child class, not base class) and use the copy constructor. QGraphicsItem includes a function called type(), which returns an int that indicates which item it is. You can also add to this in your own derived classes by implementing the type() function. For example, from the Qt docs: -
class CustomItem : public QGraphicsItem
{
...
enum { Type = UserType + 1 };
int type() const
{
// Enable the use of qgraphicsitem_cast with this item.
return Type;
}
...
};
Alternatively, if all the classes are your own type, you could use your own system.
Once you know the type, you can then copy the item with its copy constructor: -
// Example, assuming type denotes a QGraphicsItemRect
QGraphicsItemRect rect = (*originalRect);
Note that if you have inherited from QGraphicsItem and added members that are pointers, you'll need to add your own copy constructor to ensure a deep copy occurs, instead of a shallow copy.

C++ inheritance, and hiding unwanted inherited functions

I am trying to implement a QToolBar subclass, which has its items specified by a model, instead of added individually. This means a selection of functions to add/remove items (toolbar buttons), such as addAction shouldn't be publicly accessible.
What is the best way to inherit from this object, but make a selection of functions private?
My current best idea is to do like this:
class ToolbarView : public QToolBar
{
Q_OBJECT
public:
explicit ToolbarView(QWidget *parent = 0);
signals:
public slots:
private:
void addAction (QAction *action) {Q_UNUSED(action)};
QAction* addAction (const QString &text) {return QToolBar::addAction(text) ;}
...
QAction* addSeparator() {QToolBar::addSeparator();}
... [list of about 10 of these]
};
So, redefining all the functions that should not be public, as private.
Is this a good idea, or are there better methods?
As long as you inherit publicly from QToolBar, you make it possible for a client code to treat your object as such and call for example the addAction member function. If you want to ensure that these functions are inaccessible, you'll have do this the other way :
Inherit privately from QToolBar
Publicly expose the functions you wish to expose (for example with using declarations)
If you want to stick with your initial solutions and inherit publicly from QToolbar :
Be aware that it doesn't guarantee base class functions won't be called
You should consider using using declarations to change the accessibility of the base class functions instead of hiding them
Maybe you could think of this
class ToolbarView : private QToolBar
{
//...
}
In such case, all of accessible QToolBar will be with private access in your ToolbarView .
You are publically inheriting from QToolbar. How about changing that to private inheritance. That, is the class definition should begin as
class ToolbarView : private QToolBar
{
// good only if you want to
// make "most" of the public members of QToolBar private in ToolbarView
}

Using Qt signals and slots with multiple inheritance

I have a class (MyClass) that inherits most of its functionality from a Qt built-in object (QGraphicsTextItem). QGraphicsTextItem inherits indirectly from QObject. MyClass also implements an interface, MyInterface.
class MyClass : public QGraphicsTextItem, public MyInterface
I need to be able to use connect and disconnect on MyInterface*. But it appears that connect and disconnect only work on QObject* instances. Since Qt does not support multiple inheritance from QObject-derived classes, I cannot derive MyInterface from QObject. (Nor would that make much sense for an interface anyway.)
There is a discussion of the problem online, but IMO the proposed solution is fairly useless in the common case (accessing an object through its interface), because you cannot connect the signals and slots from MyInterface* but must cast it to the derived-type. Since MyClass is one of many MyInterface-derived classes, this would necessitate "code-smelly" if-this-cast-to-this-else-if-that-cast-to-that statements and defeats the purpose of the interface.
Is there a good solution to this limitation?
UPDATE: I noticed that if I dynamic_cast a MyInterface* to QObject* (because I know all MyInterface-derived classes also inherit eventually from QObject, it seems to work. That is:
MyInterface *my_interface_instance = GetInstance();
connect(dynamic_cast<QObject*>(my_interface_instance), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot()));
But this really seems like I am asking for undefined behavior....
You found the answer yourself: the dynamic_cast works as you would expect. It is not undefined behavior. If the instance of MyInterface you got is not a QObject, the cast will return null and you can guard yourself against that (which won't happen, since you said all instances of the interface are also QObjects). Remember, however, that you need RTTI turned on for it to work.
I would also offer a few other suggestions:
Use the Q_INTERFACES feature (it's not only for plug-ins). Then you'd work in terms of QObject and query for MyInterface using qobject_cast when it is really needed. I don't know your problem in detail, but since you know that all MyInterface instances are also QObjects, this seems to be the most sensible approach.
Add a QObject* asQObject() abstract method to MyInterface and implement it as { return this; } in all subclasses.
Having a QGraphicsTextItem (composition) instead of being one (inheritance).
You can declare MyInterface that takes a QObject in its constructor:
class MyInterface {
public:
MyInterface(QObject * object);
QObject * object() { return m_object; }
...
private:
QObject * m_object;
};
MyInterface::MyInterface(QObject * object) :
m_object(object)
{
...
}
Then in MyClass constructor:
MyClass::MyClass() :
MyInterface(this)
{
...
}
And you can connect the signal:
MyInterface *my_interface_instance = GetInstance();
connect(my_interface_instance->object(), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot()));