C++ структура дърво/гора за възли от различни типове класове

\\при прилагане на решение, намерено с кастинг върху общ базов клас

\\ с виртуални членове.

\\разбрах за универсални препратки, защото това е друг въпрос, създадох нов:

https://stackoverflow.com/questions/29590429/c-is-it-possible-to-use-universal-references-for-a-tree-forest-with-nodes-that

моля, вижте също този първоначален въпрос.

Искам да организирам йерархичната дървовидна структура на обекти с различни типове.

Решението трябва да върши работата си по време на компилиране, така че разбрах, че трябва да направя това с шаблони в най-добрия случай без никакво кастинг.

след някои опити, които са в editlog и имаха някои основни недостатъци.

намерих начин да го разделя на два класа

  • гора, която съхранява всички възли и им дава две координати индексните числа във вектора‹ вектор ‹...> >

  • възел шаблон ‹ T >, който съхранява T обекта и връзката с другите възли

моята идея все още няма начин за достъп до членските функции на обектите, съхранени в класа на възела, без да се нарушава уникалния_показател, който осигурява управлението на ресурсите.

и бих искал да знам как да осигуря безопасен тип при достъп до обект вътре в класа на възела.

може да има грешки вътре в кода, аз съм напълно сигурен, че няма да се компилира, въпросът е за концепцията.

Въпросите са вътре в коментарите.

версия 4:

 class Forest
 {
  public:
     template<typename T>
     {friend class Node<T>;} \\every Node<T> should have access to the forest
     Forest();
     ~Forest();
     Forest(const Forest&)=delete;  \\does not make any sense to copy or assign the forest to another forest.
     Forest operator=(const Forest&)=delete;
     int insertroot()  \\every tree has a void nullptr seed/root so that the forest does not need to be templatet, returns the treenumber
     {    \\implementation
     if(this->Nodes.size()==0)
        {
           std::vector<std::unique_ptr<Node<void> > > h0;
           h0.push_back(std::unique_ptr<Node<void>(new Node<void>(nullptr));
           this->Nodes.push_back(h0);
        }else
        {
             this->Nodes[0].push_back(std::unique_ptr<Node<void>(new Node<void>(nullptr,this)));
        }
     return this->Nodes[0].size()-1;

     }
     Node<void>* getroot(int i)   \\ to later allow access to the children and the Objects inside them
  {
     if(Nodes.size>0){
      if((i>0)&(i<Nodes[0].size()))
      {
          return Nodes[0][i].get();
      }
  }
  private:
      std::vector<std::vector<unique_ptr<Node<void> > > nodes; \\is it possible to fill this vector with any Node<T>? its a vector*2 to a unique_ptr to a classpointer with a member pointer to any class. from what i read about templates they create a extra class  for every type, so basicly the unique_ptr have a different type and i cannot store different types in a vector without casting?
 }

 template<typename T>
 class Node
 {
   public:
      Node(T n,Forest * Fo) \\ every Node is in the forest and has access to the other nodes and forest information
      :object(std::unique_ptr(n)),F(Fo)
      {
          if(n==nullptr)
          {    
               this->lvl=0;
               this->place=F->Node[0].size();
               this->parent=-1;
          }
      }
      ~Node();
      Node(const Node&)=delete;
      Node operator=(const Node&)=delete;
      T getObject(){return object.get();} \\how does the compiler know the type? see getchild 

      template<typename C>
      {
         Node<C> * getchild(int){}   \\not yet exsisting implementation of get child[int] how do i teach the compiler what int responds to what type?
                                     \\when i understand templates correct then Node<C> are different Classes for every C??
        addChild(C c)
        {
           Node * n=new Node(c,this->F);
           n->parent=this->place;
           n->lvl=this->lvl+1
           if(F->nodes.size()<=n->lvl)
           {
              n->place=0;
              h0=std::vector<unique_ptr<Node<C>> >;  
              h0.push_back(unique_ptr<Node<C>(n))
              F->Nodes.push_back(h0); \\are vector<uniptrNode<C> > and vector<uniptrNode<void>> compatible?
           }else
           {
              n->place=F->nodes[n->lvl].size();
              F->Nodes[n->lvl].push_back(unique_ptr<Node<C> >(n));
           }
           this->children.push_back(c->place);
        } 
      }        
   private:
     int parent,place,lvl;
     std::vector<int> children;
     unique_ptr<T> object;
     Forest * F;
 }

някой знае ли начин за прилагане на контейнер като този? може би има някакъв абстрактен тип тип, за който не разбрах, така че направете го, мога да добавя тип метод getnodetype(int) или checknodetype(int,type), мога ли да присвоя това с auto nodex=y->getObject()? Но как тогава компилаторът знае какви методи има и какви няма nodex?

РЕДАКТИРАНЕ: премахнах оригиналната публикация, защото v4 е много близо до работещо решение, версия 1-3 трябва да бъде в editlog


person Philipp    schedule 12.04.2015    source източник
comment
Вашият деструктор е ненужен. Съществуват контейнери и интелигентни указатели, така че да не се налага ръчно да изтривате неща.   -  person Neil Kirk    schedule 12.04.2015
comment
деструкторът е там, така че децата да бъдат deletet първи преди обекта   -  person Philipp    schedule 12.04.2015
comment
Защо това има значение? Във всеки случай децата ще бъдат изтрити преди обекта, защото се появява след него в дефиницията на класа. Ако вашият клас изисква нещата да се изтриват в определен ред, трябва да го документирате в коментар.   -  person Neil Kirk    schedule 12.04.2015
comment
Защо не използвате template<class T, class T2, class T3> …? Или да използвате T1 вместо обикновен T?   -  person Jonathan Leffler    schedule 12.04.2015
comment
защото не съм много опитен с шаблони и не знаех дали шаблоните трябва да бъдат допълнителни шаблони за публичните функции на членовете. по този начин, ако t1 е същата void или база, компилаторът генерира един клас с различни претоварвания за функцията addchild?   -  person Philipp    schedule 12.04.2015
comment
@NeilKirk Не съм сигурен, че ще има значение в моя конкретен проблем, обектите са специални QWidgets и може би трябва да се справя с премахването на вградените QWidgets преди QWidgets, в които са вградени   -  person Philipp    schedule 12.04.2015
comment
Vector може да съдържа само данни от същия тип. Така че не можете да поставите векторни обекти от тип Node‹MyNode1› и Node‹MyNode2› едновременно, защото те са различен тип.   -  person gomons    schedule 12.04.2015
comment
Мисля, че имате нужда от нещо като boost.any или QVariant. Но моето предложение, за да държат възли от различни типове в един контейнер, те се нуждаят от общ родител с виртуален метод doStuff(). Когато преминавате през дърво, просто извикайте doStuff() в базов клас. Можете да разгледате модела на посетителите.   -  person gomons    schedule 12.04.2015


Отговори (1)


Мисля, че имате нужда от нещо като boost.any или QVariant.

person gomons    schedule 12.04.2015
comment
Или std::experimental::any<>, гласуван от C++14 в отделен TS, поддържан от някои компилатори. - person набиячлэвэли; 12.04.2015