سؤال

أرغب في إنشاء فئة Notifier في لغة 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 )
    {}
};

نصائح أخرى

سيكون مقرف hack وربما ليس مضمونا للعمل، ولكن هنا فكرة أنا لا أوصي بهذا.

لنفترض أن لديك التخطيط الخاص بك كما وصفته على النحو التالي:

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عنوان ناقص نفس الإزاحة.

مرة أخرى، هذا سلوك غير محدد ولا أوصي به، ولكن من الممكن أن ينجح.

كرة القدم. " الصورة الجواب هو بداية جيدة. ومع ذلك، فإنه لا يحل مشكلة وجود أصحاب متعددة من نفس النوع. حل واحد هو الحصول على متجر المخطر قائمة المالكين بدلا من واحد. هنا هو التنفيذ السريع، لإظهار فكرة:

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

في حالة ما إذا كان لديك العديد من أنواع مختلفة من مالكي، ويمكن هذا الحل يصبح من الصعب وليس للاستخدام. في هذه الحالة، قد ترغب في النظر في المكتبات دفعة metaprogramming (<لأ href = "http://www.boost.org/doc/libs/1_38_0/libs/mpl/doc/index.html" يختلط = "نوفولو noreferrer "> 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)
  {}
};

ولكن كيف يمكن التعامل مع العديد من أصحاب 'من نفس الفئة؟ كيف يمكن للمرء أن يرث عدة مرات من 'نفس الفئة؟

لكرة القدم الإجابة ، هنا هو الحل كنت أبحث عنه:

#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