C ++ معالجة الفئة المشتقة التي تشير ذاتيا
-
29-09-2019 - |
سؤال
لذا افترض أن لدي فئة شجرة مثل هذا في 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);
}
};
بالطبع ، هذا يفترض ذلك specialNode
s دائما آخر specialNode
S كوالد/أطفال. إذا قمت بخلط Node
رمل specialNode
ق ، من الواضح أن هذا لن يعمل.