How to make a constructor equal to Qobject?

Asked

Viewed 144 times

4

When a new question arises from an old question, I want to know how to create a class equal to QObject. Basically, I want to know:

  • How to make a copy constructor that does not accept "assignment Operators"?
  • How to make a class that can delete others?
  • How to make a class similar to the QObject?
  • What does it mean to "make a copy constructor that doesn’t accept assignment Operators"? I don’t understand.

  • Object ObjetoB = ObjetoA.

  • @Lucashenrique or vc allows copy construction or does not allow, there is no way to partially remove the build by copy functionality, disabling the syntax with = but at the same time allowing direct startup Object ObjetoB{ObjetoA}. You may, as @Uilherme-Bernal did, have no copy constructor and have other constructors.

2 answers

6


Qt’s Qobject were made to work on the heap without so much difficulty with memory handling. They are uncopyable (private or deleted copy builder). In addition each object may have a relative will have zero or more children. Setting the relative of an object means adding yourself to the relative’s child list. The destructor of each object deletes all children. Note that if an object is created outside the heap, it is not recommended that it has a relative, since it will try to call delete in the son in his destrutor.

The implementation is similar to this:

#include <algorithm>
#include <vector>

class Object {
    std::vector<Object*> _children; // No QObject é usado um QList aqui
    Object* _parent = nullptr;
public:
    Object(Object* parent=nullptr) { setParent(parent); }
    Object(const Object&) = delete;

    void setParent(Object* parent) {
        if (_parent) {
            std::vector<Object*>& vec = _parent->_children;
            vec.erase(std::remove(vec.begin(), vec.end(), this), vec.end()); // remove this
        }
        _parent = parent;
        if (_parent) {
            _parent->_children.push_back(this);
        }
    }

    virtual ~Object() { // destrutor deve ser virtual, já que é uma base abstrata
        setParent(nullptr); // Se remove do seu parente
        for (Object* child : _children)
            delete child; // deleta todos os filhos e, por recursão, seus filhos
    }
};
  • @Lucashenrique missed a _ there in the destructor. Corrected.

  • Qt allows you to declare objects on the stack. It’s perfectly possible to do QObject a; QObject b(&a); QObject c(&b);. Destructors are called in reverse order to the statement, each of them removing the destroyed object from the father’s list of children.

  • @C.E.Gesser This is a particular case where the destruction order removes the objects of the relatives before they have a chance to deleteAlos. Observe QObject a; QObject b; a.setParent(&b);. Crash!

  • @Lucashenrique The best example of this is Qt himself. Allow to allocate objects in the heap without worrying about destroying them, creating a hierarchical structure. It’s almost like a kind of garbage collector.

  • @Lucashenrique Qt leaves the private copy builder in some cases, but implements in others, mainly in classes that represent shared resources, such as QImage. You can create copies of them, although internally they all point to the same resource.

  • @C.E.Gesser Important to note that the QImage is not a QObject. As with all containers and strings. These classes share data so they are fairly light and can be copied everywhere. Nor does it make sense that they are allocated in the heap.

  • 1

    @Guilhermebernal Truth, this distinction is not very clear in Qt. You have objects with shared semantics, such as Qimage, whose copy creates more references, others with unique semantics, such as Qobject derivatives, uncopyable, and even small objects, such as Qpoint, with value semantics. And all you can know is how to do it from documentation or looking at the code.

  • If I had a class derived by hierarchy, how could I pass it in the "Object parameter"?

  • class B : public QObject {...}; QObject a(new B); that?

Show 4 more comments

3

Qobject has within it a list of children. Something like:

class QObject {
  std::vector<QObject*> children;
  QObject *parent;
};

The constructor basically stores the parent and adds the object to its list

QObjec(QObject *parent) : parent(parent) {      
  if (parent)
    parent->children.push_back(this);
} 

The magic stays in the destructor. He has to destroy all the children. That’s easy. But he has to take care if he is someone’s son, you need to remove yourself from his list to avoid one delete double.

virtual ~QObject() {
  if (parent) 
    parent->removeChild(this);

  for (unsigned i=0; i<children.size(); ++i) {
    delete children[i];
  }
}

The destructor must be virtual, because at the time of invoking it we want it to be called the destructor of the correct class, and only of Qobject. To remove yourself from the father’s list, something like this could be done:

QObject::removeChild(QObject *child) {
  std::vector<QObject*>::iterator iter = std::remove(children.begin(), children.end(), child);
  children.erase(iter, children.end());
}

I just don’t understand much yet what you mean by builder who doesn’t accept assignments.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.