Question

Je voudrais créer en C ++ une classe notificateur que je vais utiliser dans d'autres objets pour notifier divers supports lorsque l'objet est détruit.

template <class Owner>
class Notifier<Owner> {
public:
  Notifier(Owner* owner);
  ~Notifier(); // Notifies the owner that an object is destroyed
};

class Owner;

class Owned {
public:
  Owned(Owner* owner);
private:
  Notifier<Owner> _notifier;
};

Mon point est que j'ai un objet graphique dense et complexe, je voudrais éviter de stocker l'adresse de l'objet appartenant au déclarant. Est-il possible de changer ma classe de notification afin qu'il puisse en déduire l'adresse de l'objet appartenant à son propre adresse et un décalage qui serait calculé au moment de la compilation?

Notez également que tout objet peut notifier plusieurs « propriétaires », peut-être de la même classe.

Merci.

Était-ce utile?

La solution

Ou quelque chose comme ceci:

Hériter de votre notificateur et ajoutez comme paramètre Propriété modèle. Ensuite, vous pouvez avoir une méthode propriété disponible à l'intérieur du déclarant:

template < class Owner , class Owned >
class Notifier
{
public:
    Notifier(Owner* owner)
    {}

    Owned * owned()
    { return static_cast< Owned * >( this ); }

    ~Notifier()
    {
        // notify owner with owned()
    }
};

class Owner
{};

class Owned : public Notifier< Owner , Owned >
{
public:
    Owned( Owner * owner ) : Notifier< Owner , Owned >( owner )
    {}
};

Autres conseils

Jetez un oeil à la GoF Design Observer Patter .

Il serait méchant pirater et probablement pas garanti, mais voici une pensée Je ne recommande pas .

Supposons que vous ayez votre mise en page comme vous avez décrit comme ceci:

template <class Owner>
class Notifier<Owner> {
public:
  Notifier(Owner* owner);
  ~Notifier(); // Notifies the owner that an object is destroyed
};

class Owner;

class Owned {
public:
  Owned(Owner* owner);
private:
  Notifier<Owner> _notifier;
};

Si _notifier connaît son nom, il pourrait calculer l'adresse de Owned comme celui-ci (qui est exécuté dans le constructeur du Notifier):

Owned *p = reinterpret_cast<Owned *>(reinterpret_cast<char *>(this) - offsetof(Owned, _notifier));

En fait, l'hypothèse est que _notifier est à un décalage fixe au sein de la catégorie détenues en propriété. Par conséquent, l'adresse est égale à Owned Minus adresse de _notifier même décalage.

Encore une fois, ce comportement est indéfini que je ne recommanderais pas, mais pourrait éventuellement travailler.

fa « . s réponse est un bon début. Cependant, il ne résout pas le problème d'avoir plusieurs propriétaires du même type. Une solution est d'avoir le magasin de notificateur une liste des propriétaires au lieu d'un seul. Voici une mise en œuvre rapide, pour montrer l'idée:

template <typename Owner, typename Owned>
class Notifier
{
  protected:
    Notifier()
    {}

    // Constructor taking a single owner
    Notifier(Owner & o) 
    { 
        owners.push_back(&o); 
    }

    // Constructor taking a range of owners
    template <typename InputIterator>
    Notifier(InputIterator firstOwner, InputIterator lastOwner)
        : owners(firstOwner, lastOwner) {}

    ~Notifier()
    {
        OwnerList::const_iterator it = owners.begin();
        OwnerList::const_iterator end = owners.end();
        for ( ; it != end ; ++it)
        {
            (*it)->notify(static_cast<Owned*>(this));
        }
    }

    // Method for adding a new owner
    void addOwner(Owner & o) 
    { 
        owners.push_back(&o); 
    }

private:
    typedef std::vector<Owner *> OwnerList;
    OwnerList owners;
};

Vous pouvez l'utiliser de cette façon:

class Owner;

class Owned : public Notifier<Owner, Owned>
{
    typedef Notifier<Owner, Owned> base;

    //Some possible constructors:
    Owned(Owner & o) : base(o) { }

    Owned(Owner & o1, Owner & o2)
    {
        base::addOwner(o1); //qualified call of base::addOwner
        base::addOwner(o2); //in case there are other bases
    }

    Owned(std::list<Owner*> lo) : base(lo.begin(), lo.end()) { }
};

Dans le cas où vous avez beaucoup de différents types de propriétaires, cette solution peut devenir assez difficile à utiliser. Dans ce cas, vous pouvez regarder les bibliothèques métaprogrammation boost ( MPL , Fusion ), avec laquelle vous pourriez vous retrouver avec un code qui vous permettent de faire des étoffes comme ça:

class Owned : public Notifier<Owned, OwnerType1, OwnerType1, OwnerType2>
{
    Owned(OwnerType1 & o1, OwnerType1 & o2, OwnerType2 & o3) 
        : base(o1,o2,o3)
};

Cependant, la mise en œuvre de cette solution serait un peu plus que le précédent.

Une partie de la solution serait d'avoir été propriétaire Hériter de notificateur. De cette façon, l'adresse de l'objet détruit est tout simplement « ceci » ...

class Owned : public Notifier<Owner> {
public:
  Owned(Owner* owner) 
    : Notifier<Owner>(owner)
  {}
};

Mais comment gérer plusieurs « propriétaires » de la même classe? Comment peut-on hériter plusieurs fois de la «même classe?

Merci fa de répondre , voici la solution que je cherchais:

#include <iostream>

template <class Owner, class Owned, int = 0>
class Notifier {
public:
  Notifier(Owner* owner)
    : _owner(owner)
  {}
  ~Notifier() {
    _owner->remove(owned());
  }
  Owned * owned(){ 
    return static_cast< Owned * >( this ); 
  }

private:
  Owner* _owner;
};

class Owner {
public:
  void remove(void* any) {
    std::cout << any << std::endl;
  }
};

class Owned : public Notifier<Owner,Owned,1>, Notifier<Owner,Owned,2> {
public:
  Owned(Owner* owner1, Owner* owner2)
    : Notifier<Owner,Owned,1>(owner1)
    , Notifier<Owner,Owned,2>(owner2)
  {}
};

int main() {
  std::cout << sizeof(Owned) << std::endl;
  Owner owner1;
  Owner owner2;
  Owned owned(&owner1, &owner2);
  std::cout << "Owned:" << (void*)&owned << std::endl << std::endl;
}

Merci!

Je doute fortement. Il n'y a aucun moyen pour le savoir notificateur qu'il a été utilisé dans la composition. Que faire si je fais

class Foo
{
private:
  Notifier _a, _b, _c;
}

J'aimerais me tromper bien, mais je doute vraiment que c'est faisable sans donner explicitement plus d'informations sur le notificateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top