我想在C ++,我将在其他对象使用时,对象被销毁,以通知各个持有人通告类来创建。

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;
};

我的观点是因为我有一个致密的和复杂的对象图,我想避免存储拥有对象的地址的通知。有没有办法改变我的通知类,以便它可以从它自己的地址推断所拥有的对象的地址,并且会在编译时计算的?偏移

还要注意的是任何对象可以具有从同一类通知几个“所有者”,可能。

感谢。

有帮助吗?

解决方案

或者是这样的:

从您的通知继承和新增自有作为模板参数。然后你就可以有可用的通知内资方法:

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 )
    {}
};

其他提示

这将是一个讨厌破解,可能无法保证正常工作,但这里有一个想法的我不建议这样做

假设你有你的布局像你这样的描述:

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;
};

如果_notifier知道它的名字,它可以计算这样Owned的地址(这是在Notifier的构造执行):

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

基本上,假设是_notifier是在一些固定在所属类内的偏移。因此的拥有的地址等于_notifier的地址减去相同的偏移。

再次,这是不确定的行为,我不建议,但能够工作。

FA“。的回答是一个良好的开端。但是,它不能解决具有相同类型的多个所有者的问题。一个解决方案是有通知店主,而不是单一的一个列表。这里是一个快速的实现,展现了主意:

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;
};

您可以使用这种方式:

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()) { }
};

在这里你有很多不同类型的业主的情况下,该解决方案可以变得相当难用。在这种情况下,你可能想看看升压元编程库(的 MPL 融合),与你可能最终与让你做这样的东西一个代码:

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

然而,实施此解决方案将是比前一个时间稍长。

的解决方案的一部分。将已经从通知拥有继承。以这种方式,被破坏的对象的地址是简单的“本” ...

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

但如何从同一类处理多个“主人”?怎样才能从“同一类”?

继承几次

由于 FA的回答,这里是我一直在寻找的解决方案:

#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;
}

谢谢!

我高度怀疑。没有办法的通知才知道它已经组成被使用。如果我做什么

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

我喜欢,虽然被证明是错误的,但我真的怀疑这是可行的,而不该通知明确给出更多的信息。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top