سؤال

لذا افترض أن لدي فئة شجرة مثل هذا في C ++

class Node{
    void addChild(Node*);
    /*obvious stuff*/
    protected:
        Node* parent;
        vector<Node*> children
}

class specialNode : public Node{
    void addChild(specialNode*);
    /*obvious stuff*/
    /*special stuff*/
}

الآن كلما وصلت إلى الأطفال في SpecialTree ، من الواضح أنني أحصل على عقدة*، وليس خاصة*.

لكن هذا خاص* يحتوي على متغيرات أعضاء ووظائف لا تملكها العقدة.

يمكنني إجبار SpecialNode على أخذنا فقط كأطفال وخلاف ذلك في وقت الترجمة ، لكنني ما زلت أحصل على عقدة* عند الوصول إلى الأطفال/الوالدين ، وعلي أن ألقيها كلما أردت استخدام وظائف خاصة ، حتى في وظائف node الخاصة.

هل هناك أي طريقة ذكية ، أو أي طريقة أفضل للقيام بهذا؟ بخلاف الصب حرفيا في كل مرة؟

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

المحلول

إذا كنت بحاجة فقط SpecialNode الكائنات الموجودة في شجرتك (وتريد فقط تغليف جميع وظائف الأشجار العامة في Node) تستطيع فعل Node فئة ما يسمى "mix-in" مثل

template <class N>
class Node : public N {
public:
  void addChild(Node<N>*);
protected:
  Node<N>* parent;
  vector<Node<N>*> children;
};

class SpecialNodeBase {
  // Here comes all "special" data/methods for your "special" tree
};

typedef Node<SpecialNodeBase> SpecialNode;

بعد ذلك يمكنك بناء شجرة SpecialNode الكائنات واستخدام جميع الطرق من SpecialNodeBase وكذلك وظائف إدارة الأشجار الإضافية من Node

نصائح أخرى

نظرًا لأن وظيفة AddChild في فئة طفلك ليست تعدد الأشكال ، اجعلها افتراضية ، ولكن لا يُسمح بوظائف التحميل الزائد عبر أعضاء القاعدة/الطفل ، لذلك يتعين علينا تغيير معلمة AddChild في فئة الطفل:

class Node{
    virtual void addChild(Node*);
    ...
}

class specialNode : public Node{
    virtual void addChild(Node*);
    ...
}

الآن ، يجب أن تعمل.


إذا كنت تريد الوصول إلى childeren متغير من فئة الطفل (specialNode الفصل) ، يجب أن يلقيها. فمثلا:

specialNode* var = static_cast<specialNode*>(children[i]);

نظرًا لأننا أعلننا AddChild كدالة افتراضية ، فيجب علينا استخدامه dynamic_cast بدلاً من static_cast إذا لم نكن متأكدين من ذلك children[i] هو دائما مثال specialNode الطبقة ، وبالتالي من الأفضل الاستخدام dynamic_cast:

specialNode* var = dynamic_cast<specialNode*>(children[i]);
if(var != NULL)
{
    //...
}

إذا فهمت بشكل صحيح ، فلن يسمح لك حل فئة "Mix-In" بالاتصال addChild من الوظائف التي تنفذها SpecialNodeBaseClass.

يمكنك فعل ما يلي في الواقع:

template <class recursiveT>
class Base {
public:

     Base(dataType data) { populate children with data; }

     void addChild() { something base class appropriate; }

protected:
     std::vector<recursiveT> children;
};




class Derived: public Base<Derived> {
public:
     /* note: the constructor here will actually call the 
        constuctor of the base class */
     Derived(dataType data) : Base<Derived>(data) {} 
     /* other special functions go here.  */
};

قد يبدو هذا مجنونًا بعض الشيء ، لكنه يجمع بشكل نظيف بالنسبة لي على العديد من إصدارات GCC ، لذا فأنا أميل إلى الاعتقاد بأنه ليس خاطئًا تمامًا. يجب أن تكون قادرًا الآن على استدعاء وظائف القاعدة من الداخل المشتقة.

سيكون عليك بالتأكيد إلقاء Node * إلى specialNode * في مرحلة ما ، ولكن يمكنك جعل هذا نظيفًا وسهل الإدارة عن طريق القيام بذلك في مكان واحد فقط. يمكنك إضافة وظيفة عضو ، على سبيل المثال getParent وتجاوزه في specialNode, ، مثله:

class Node {
  ...
  virtual Node *getParent() {
    return parent;
  }
};

class specialNode : public Node {
  ...
  specialNode *getParent() {
    return dynamic_cast<specialNode *>(parent);
  }
};

بالطبع ، هذا يفترض ذلك specialNodes دائما آخر specialNodeS كوالد/أطفال. إذا قمت بخلط Nodeرمل specialNodeق ، من الواضح أن هذا لن يعمل.

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