سؤال

لدي فئة يدعى الجسيمات التي لديها STD :: تعيين كعضو. فئة تبدو وكأنها هذه:

class Particle {
private:
    std::set<vtkIdType> cells;
    std::set<vtkIdType>::iterator ipc;

public:

    Particle() {};

    enum state {EXISTS = -1, SUCCESS = 0, ERROR = 1};

    state addCell(const vtkIdType cell);

    int numCells() { return static_cast<int>(cells.size()); }

    vtkIdType getFirstCell() { return (*(ipc = this->cells.begin()));}
    vtkIdType getNextCell() { return *(++ipc); }
    vtkIdType hasNextCell() { ++ipc; if (ipc == this->cells.end()) return false; --ipc; return true; }

    std::string getOutput();
};

أنا غير سعيد للغاية مع getFirstCell(), getNextCell() وخاصة hasNextCell(), ، لديهم لأنني لا أريد أن أعرض مجموعة نفسها. اضطررت لاستخدام الطريق من خلال ++ipc و --ipc لأن if((ipc+1) == this->cells.end()) يعطي خطأ مترجم، ويبدو أن IPC + 1 هي المشكلة.

ماذا ستكون طريقة جيدة لتغليف مجموعة والوصول إليها؟ أيضا، هل هناك طريقة لطيفة للتخلص من getFirstCell() وظيفة؟

شكرا مقدما.

تحرير: الرمز الذي نشرته هو مجرد مثال على بنية الفئات. تحتوي الفئة "الحقيقية" على مجموعات أخرى وغيرها من البيانات غير المهمة لهذا السؤال (افترضت).

هل كانت مفيدة؟

المحلول

لست متأكدا من السبب في عدم رغبتك في عدم اكتشاف الإعداد نفسه، ولكن إذا أردت أن تضمن التأكد من أن محتوى المجموعة لا يمكن تغييرها في الخارج class Particle فقط العودة const المحامون الذين يجعلون مجموعة "للقراءة فقط"، على سبيل المثال

typedef std::set<vtkIdType>::const_iterator CellIterator;
CellIterator beginCell() const { return this->cells.begin(); }
CellIterator endCell() const { return this->cells.end(); }

نصائح أخرى

السبب في أن ipc+1 لا يعمل هو ذلك std::set يدعم فقط المزارعين ثنائي الاتجاه، مما يدعم operator++ و operator--; ؛ لكي تستخدم operator+, تحتاج إلى استخدام محاماة الوصول العشوائي.

أحد القلق الذي أراه مع تصميمك هو أن وظائفك تسمى مثل الملحقات (Getsuchandsuch) لكنها أيضا تعديل الحالة الداخلية للكائن (ipc هو تعديل). هذا قد يؤدي إلى الارتباك.

شيء واحد يمكن أن تحاول هو استخدام بعض وظائف الأعضاء التي ترجع المحامي (أ begin و end, ، على سبيل المثال)، والسماح للمستخدمين في صفك استخدام المحفزين للوصول إلى المجموعة الداخلية، مع الاستمرار في توسيع نطاق التطبيق.

يمكنك إرجاع نوع ITERATOR الخاص بمجموعة أو إذا كنت تريد المزيد من التحكم أو التغليف، فيمكنك تطبيق فئة ITERATOR الخاصة بك التي تتفاؤ مع جهاز ITERATOR SET.

لمنع تعريض مجموعة :: ITERATOR (لعدم الوعد للمستخدمين أكثر من اللازم)، يمكنك إنشاء غلاف:

class Particle::iterator
{
public:
  iterator()
  {}
  iterator &operator++()
  {
    ++InternalIterator;
    return *this;
  }
  vtkIdType &operator*() const
  {
    return *InternalIterator;
  }
  ...//other functionality required by your iterator's contract in the same way
private:
  iterator(const std::set<vtkIdType> &internalIterator)
    :InternalIterator(internalIterator)
  {}
  std::set<vtkIdType>::iterator InternalIterator;
};

Particle::iterator Particle::GetBeginCell()
{
  return iterator(cells.begin());
}
Particle::iterator Particle::GetEndCell()
{
  return iterator(cells.end());
}

وبالتالي، سوف تتخلص من المحفز الداخلي (لأنه مقيد للغاية لتكون قادرا على أن يكون بإمكانية الحصول على جهاز كمتصل به واحد فقط) وستحصل على القدرة على استخدام الخوارزميات من STL على محاخات الجسيمات.

أيضا زيادة :: Iterator_Facade قد تكون مفيدة هنا ...

السؤال هو حقا ما تحاول إنجازه هنا. الآن، يبدو أن صفك (على الأقل بالنسبة لي) للقيام بأذى أكبر من الخير - إنه يجعل العمل مع محتويات المجموعة أكثر صعوبة بدلا من أسهل.

أود أن أنظر إلى الجسيمات، ومعرفة ما إذا كان يمكن أن توفر شيئا ذا معنى إلى جانب بعض طريقة تخزين / الوصول إلى مجموعة من الخلايا. إذا كان حقا مجرد حاوية بسيطة، فستكون أفضل بكثير من شيء مثل typedef std::set<cell> Particle;, ، لذلك يمكن للمستخدم النهائي استخدام الخوارزميات ومثل هذه المجموعة تماما مثلما يمكن لأي شيء آخر. أنا فقط أكتب فئة لتغليف ذلك إذا كنت تستطيع أن تغليف شيء مفيد للغاية - أي إذا كان لديك Particle يمكن للفئة أن تجسد بعض "المعرفة" حول الجسيمات حتى يمكن أن يعمل رمز آخر مع جسيم كشيء مفيد في حد ذاته.

الآن، الخاص بك Particle ليس سوى حاوية - ولا يبدو وكأنه حاوية جيدة بشكل خاص أيضا. ما لم تتمكن حقا من إضافة شيء ما، قد تكون أفضل حالا فقط باستخدام ما هو موجود بالفعل.

ما تظهره لا يفعل أي شيء إلى جانب الحجدا الثلاثة. تغليف المجموعة عن طريق إجراء العمليات التي ستستخدم جزء Getters هؤلاء من فئة الجسيمات، فلن تحتاج إلى Getters على الإطلاق: Voila، مغلف.

إذا كنت ترغب في الاحتفاظ بالتنفيذ العام لديك بالفعل، ولكن ببساطة القضاء getFirstCell(), ، يمكنك تهيئة IPC داخل المنشئ. كما هو مذكور أعلاه، واستخدام يحكم const وتوضيح واضح بين مسافر وموتورز يوضح الواجهة. بالإضافة إلى ذلك، إذا كنت تقوم بتنفيذ المحامون في صفك، فسوف أوصي بذلك addcell() إرجاع جهاز استئناف يشير إلى الخلية الجديدة، وبدلا من ذلك رمي استثناء عند مواجه خطأ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top