문제

C ++에서 다른 객체에서 사용하여 개체가 파괴 될 때 다양한 홀더에 알리는 알림 클래스를 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;
};

내 요점은 조밀하고 복잡한 객체 그래프를 가지고 있기 때문에 알림에 소유 한 객체의 주소를 저장하지 않기를 원합니다. 자체 주소와 컴파일 타임에 계산할 오프셋에서 소유 한 객체의 주소를 추론 할 수 있도록 Notifier 클래스를 변경할 수있는 방법이 있습니까?

또한 모든 객체는 동일한 클래스에서 여러 '소유자'를 알릴 수 있습니다.

감사.

도움이 되었습니까?

해결책

또는 다음과 같은 것 :

Notifier에서 상속하고 소유 한 템플릿 매개 변수로 추가하십시오. 그런 다음 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 )
    {}
};

다른 팁

살펴보십시오 GOF 옵저버 설계 패턴.

그것은 될 것입니다 끔찍한 해킹하고 아마도 작동하지는 않지만 여기에 생각이 있습니다. 나는 이것을 추천하지 않는다.

다음과 같이 설명한 것처럼 레이아웃이 있다고 가정 해 봅시다.

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.의 대답 좋은 시작입니다. 그러나 동일한 유형의 여러 소유자가있는 문제를 해결하지 못합니다. 한 가지 해결책은 Notifier Store에 단일 소유자 대신 소유자 목록을 제공하는 것입니다. 다음은 아이디어를 보여주기위한 빠른 구현입니다.

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

다양한 유형의 소유자가있는 경우이 솔루션은 사용하기가 다소 어려워 질 수 있습니다. 이 경우 Boost Metaprogramming 라이브러리를보고 싶을 수도 있습니다 (MPL, 퓨전), 당신은 당신이 그런 것들을 할 수있는 코드로 끝날 수 있습니다.

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

그러나이 솔루션을 구현하는 것은 이전 솔루션보다 약간 길다.

솔루션의 일부는 Notifier의 상속을 소유 한 것입니다. 이런 식으로, 파괴 된 물체의 주소는 단순히 '이것'입니다 ...

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