C ++ обрабатывает производный класс, который сам ссылается - PullRequest
1 голос
/ 18 августа 2010

Итак, предположим, у меня есть класс дерева, как это в 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, я, очевидно, получаю Node *, а не specialNode *.

Но этот specialNode * имеет переменные-члены и функции, которых нет у Node.

Я могу заставить specialNode брать только specialNode в качестве дочерних, и в противном случае прерывать во время компиляции, но я по-прежнему получаю Node * при доступе к children / parent, и мне приходится приводить его всякий раз, когда я хочу использовать специальные функции, даже в функциях specialNode.

Есть ли какой-нибудь умный или просто лучший способ сделать это? Кроме буквального литья каждый раз?

Ответы [ 4 ]

4 голосов
/ 18 августа 2010

Если вам нужны только SpecialNode объекты в вашем дереве (и вы просто хотите инкапсулировать все функциональные возможности общего дерева в Node), вы можете сделать Node так называемым смешанным классом, таким как

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

0 голосов
/ 12 февраля 2011

Если я правильно понимаю, решение класса "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, поэтому я склонен полагать, что это не совсем неправильно.Теперь вы должны иметь возможность вызывать функции Base из Derived.

0 голосов
/ 18 августа 2010

В определенный момент вам определенно придется привести 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 с, это явно не сработает.

0 голосов
/ 18 августа 2010

Поскольку функция addChild в вашем дочернем классе не является полиморфизмом, сделайте ее виртуальной, но перегрузка функций между базовыми / дочерними членами недопустима, поэтому мы должны изменить параметр addChild в дочернем классе:

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

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

Теперь это должно сработать.


Если вы хотите получить доступ к переменной childeren из дочернего класса (specialNode class), вам следует привести его.Например:

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)
{
    //...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...