I have a subclass of QTreeWidget, and I want to do some operation such as
class MyTree(QTreeWidget):
def mouseMoveEvent(self, event):
super(MyTreeWidget,self).mouseMoveEvent(event)
event = QMouseEvent(event)
It seems that MyTree type has changed to MyTree, I cannot call QTreeWidget method itemAt unless I use super key word like this:
super(MyTreeWidget,self).itemAt(event.globalPos())
Is there a similar method to qobject_cast in PyQt? I know qobject_cast exists in Qt.
There is no equivalent of qobject_cast in PyQt. If you wish to access an overridden superclass method, you must use super.
In C++, you can have a variable declared as a pointer to one type QObject * when it actually points to an object of a derived type. For example:
QObject *obj = new QWidget;
I don't know C++ well enough to say whether methods are determined at compile time or run time. In other words, if you then have
obj->someQObjectMethodOverriddenInQWidget(...);
then I'm not sure whether this will call the QObject or QWidget method. (I would guess that it would be the QObject method; it seems you want to use qobject_cast to cast an object to the superclass in order to call overridden superclass methods, and if this didn't happen you wouldn't be wanting to use qobject_cast.)
On the other hand, Python has no type information available at compile time; it relies solely on the run-time type of an object to determine which method to call. If you have overridden a method in a subclass, and you want to call the overridden method from the superclass, you must use super. On the other hand, if MyTree does not override itemAt, you should just be able to call self.itemAt(...), as it will inherit itemAt from its superclass.
Related
Part of my code are two C++ classes 'ClassA' and 'ClassB' which are both inherited from QObject.
And in some of its methods ClassB needs to syncronously request data stored in ClassA.
ClassA <----- request data ----- ClassB
Is there Qt API similar to signals/slots which can be used for it?
There are two possible options which I can think of but I am not sure
if they are architecturally correct:
1) To define Q_INVOKABLE function in ClassA which would return the needed data as its return value and to call it in ClassB.
But I am not sure if Q_INVOKABLE can be used for purposes other than C++/QML bonding and how to register it properly in other cases.
2) To create regular signal/slot pair in ClassB/ClassA respectively.
signal emitted in ClassB would be used to request the data from ClassA and would have a pointer as its input arg which would point to where store the data.
And slot in ClassA would write the data to this pointer.
void ClassA::slot(type *ptr)
{
// write data to ptr
}
void ClassB::signal(type *ptr)
Sounds like you want dependency injection. That's a fancy word for simply giving reference of class A to class B, probably as a constructor parameter.
Use QPointer<ClassA> if you can decide it's ClassA when writing the source code. Then just call any methods of ClassA as needed.
If you can't lock the exact class, just know it will be QObject, then use QPointer<QObject> and use Qt properties or invokable methods (Q_INVOKABLE or just a slot with a return value) to request what you want.
As an alternative, if ClassB instance can own an instance of ClassA, just give a pointer to ClassA instance to B, and then make B set itself as parent of A. Then it'll be automatically deleted by the destructor (the usual Qt way of QObject ownership).
In C++, I have Parent class. Child1, Child2, etc. inherit from it. Classes Child1, Child2, etc. share some methods of the parent and have their own methods.
I declare a vector to be able to add any child of Parent.
vector<Parent*> v = {new Child1(), new Child2(),...};
Depending on a child, I want to define different behaviour for a method of BClass::someMethod(Child1* child), BClass::someMethod(Child2* child)... Something like Visitor pattern. The problem is that I must pass an element of v vector into BClass::someMethod(...) and the compiler says, for example for method BClass::someMethod(Child1* c1) when v[0] is passed:
Argument of type Parent* is incompatible with parameter of type Child1*
Could you please tell me how to overcome the issue?
OOP solution is to add a virtual member function to Parent, implement the different behaviour in overridden member functions of children, and change the argument of BClass::someMethod to a Parent pointer (or reference), and call the virtual function in there - or get rid of BClass::someMethod entirely, and use the virtual function directly in case BClass::someMethod no longer has other functionality.
P.S. Storing dynamic allocations in bare pointers is not a good design. Smart pointers are recommended instead.
There is a parent class, and there are two child class extends the parent class: child1,child2, I see the children as parent class, like this:
function(Parent *c){
c->someMethod();
}
but child has a method which child2 doesn't have. I try to add a if statement to judge whether the class is child1 like this:
function(Parent *c){
if(c->getType() == 'child1'){
c->someMethod();
}
}
but there comes the error:'class Parent' has no member named 'someMethod' so, how to deal with it?
Since you are working with pointer to Parent, you can only call methods, which Parent type have.
So, the first solution is to put all necessary methods in Parent class and override them in children classes. This is far more preferable than next one.
Another possible solution is to dynamic_cast Parent pointer to necessary child pointer, if you are sure, that it's correct one and call method on child pointer. This is sign of bad design, and I'd recommend to stick to first solution.
Try dynamic_casting it to the correct type. If it is not possible, the cast should return a nullptr (or NULL).
To elaborate on the ambiguous title, I'd like to roughly know how the meta system works dynamically.
When working with slots/property accessors in a static context the calls are probably inlined, after all if it is possible why not??
But what about dynamic scenarios and querying for indices? How is the meta object implemented? Is the offset one of a pointer in a virtual table? Or maybe Qt creates its own vtable instead the one used by the class virtual methods? In this case, are virtual property methods duplicated in both the class "native" vtable as well as the hypothetical extra one created for the static meta object? Are the actual calls technically virtual?
I am not interest in intricate details, more like the overall concept.
First of all, there is no such thing as a "virtual table" when portable C++ is concerned. It's an implementation detail, hidden by the compiler. There's no way to portably access its internals (the implementation's data structure), only its semantics (the functionality it offers).
Secondly, you don't say what you mean by a "call". Assume we have
class BaseObject : public QObject {
Q_OBJECT
public:
Q_SIGNAL void mySignal();
}
class MyObject : public BaseObject {
Q_OBJECT
public:
Q_SLOT void mySlot();
};
MyObject myObject;
There are multiple ways of invoking mySlot.
Calling it directly:
myObject.mySlot("yay!")
This is no different than calling any other method - just because it's a slot, doesn't make it special from C++'s point of view. If it happens to be a virtual method, it's a virtual method call, with any overheads this entails on a given platform.
By using the virtual qt_metacall method with the method index:
myObject.qt_metacall(QMetaObject::InvokeMetaMethod, 4, nullptr);
The implementation of qt_metacall is generated by moc. The qt_metacall is where the method indices get defined. Internally, qt_metacall calls itself recursively all the way into QObject::qt_metacall.
Each implementation checks if the method index is less than the number of metamethods on this class. The constant data record with this information is generated by moc. For example, QObject has three metamethods - the two signals and one slot. If the index is too larger than 2, it is decremented by the number of metamethods and returned to the next derived class's qt_metacall.
When QObject::qt_metacall returns into BaseObject::qt_metacall, the index has been decremented by 3, and is now one (4-3 = 1). Since BaseObject has only one metamethod (index 0), this index is decremented by one and returned.
When BaseObject::qt_metacall returns into MyObject::qt_metacall, the index has been decremented by (3+1=4), and is now zero (0). That's the local index of the lone mySlot, and call is handled by passing the index to MyObject::qt_static_metacall.
By using the static qt_static_metacall (it's a private method, though):
MyObject::qt_static_metacall(&myObject, QMetaObject::InvokeMethod, 0, nullptr);
The qt_static_metacall is a static method that implements the actual call. It simply switches on the local, 0-based index, and calls the method, passing any arguments it needs. The pointers-to-arguments are passed in the last argument - here it's simply a nullptr since there are no arguments. This is plain boring C++ code, no magic there.
We use the knowledge that the method with index 4 is really a method on MyObject (and not, say, QObject or BaseObject). Since all the base classes together use up 4 indices, we adjust the method index down by the same amount - to zero (4-4 = 0).
So, if you know what concrete class implements the method index, you can call the static method directly without using the recursive virtual qt_metacall. This lookup is performed by QObject::connect when the connection is being set up. The connection's destination is stored as a local method index and a pointer to the qt_static_metacall method of the class that has given method. This saves the cost of recursion of qt_metacall when the slot is invoked by the connected signal.
By using QMetaObject::invokeMethod:
QMetaObject::invokeMethod(&myObject, "mySlot");
This performs all the same lookups as QObject::connect does, but instead of setting up a connection, it executes the call right away. Again, it will end in MyObject::qt_static_metacall.
By using QMetaMethod::invoke:
QMetaMethod method = myObject.metaObject()->method(
myObject.metaObject->indexOfSlot("mySlot()"));
method.invoke(myObject);
The QMetaObject caches the looked-up pointer to MyObject::qt_static_metacall as well as the local method index 0. Thus the invoke call has less overhead than the one from QMetaObject.
I read one of the book which deals with the issues of member function binding in c++.
and it's giving the next example:
void Window::oops() { printf("Window oops\n"); }
void TextWindow::oops() {
printf("TextWindow oops %d\n", cursorLocation);
Window win;
Window *winPtr;
TextWindow *txtWinPrt = new TextWindow;
win = *txtWinPrt;
winPtr = txtWinPtr;
win.oops(); // executes Window version
winPtr->oops(); // executes TextWindow or Window version;
I didn't understand why win.oops would executes window version? win is defined as Textwindow.
Thank you for your help.
This is caused by slicing. If you assign to an object of the super-class, the information from the subclass is lost. The problem is this statement:
win = *txtWinPrt;
Since you assign an object of a subclass (TextWindow) to an object of the super-class (Window), all the information of TextWindow that is not in Window is sliced away.
Window win
is an object of Window class. It should be pointer or reference to call derived class method with base class instance.
Two things are needed for dynamic polymorphism using object orientation (which is what you are asking for).
Window and Textwindow need to implement the "is-a" relationship. (so, class TextWindow : public Window {});
A virtual function is needed in a base-clase in order to get runtime polymorphism, generally a destructor if you cannot find a virtual function naturally. A virtual function causes the compiler to put down a v-table.
Without these two things, the compiler will not put a v-table down at callsites. The v-tables enables runtime polymorphism as function calls are indirected through it.
Alternatively you could resort to c-style function pointers, or something like boost::bind. But this defeats OO programming. I personally use a v-table very rarely.