Probleme bei Baum Implementation mit Template-Klasse zur Verwaltung

pointhi

Erfahrenes Mitglied
Hy, ich hatte schon mal eine Thread hier wegen einem ähnlichen problem. Ich hab die gesammte Klasse neu geschrieben, und setze dabei auch neue methoden ein um das gewünschte Ziel zu erreichen.

Ich hab den Sourcecode des aktuellen statuses auf GitHub zur Verfügung gestellt, und beziehe mich auf diesen.

Hier eine kleine erklärung von dem was ich mir vorgestellt habe:

Baseclass ist eine abstrakte klasse um grundlegende variablen und funktionen zu deklarieren die programmweit nutzbar sein sollen.

TreeHandler ist die Template-Implementierung von der abstrakten Klasse "Baseclass", ich hätte die Funktionen in die einzelnen klassen hineinschreiben können, dann würde es wohl schon funktionieren, aber ich will redundanz so gut wie möglich vermeiden. Das Problem liegt vermutlich bei dieser Klasse

MainHandler ist die Grundklasse von der sich der Baum aufbaut.

Hardware::Hardware
Hardware::I2cSlave::I2cSlave Das sind klassen die dafür sorgen sollen dass im Baum nur bestimmte Elemente aufgenommen werden dürfen. Ich hab eine kleine Grafik gezeichnet die das ilustrieren soll:

Hardware::I2c
Hardware::I2cSlave::Slave Das sind die Klassen die später die arbeit durchführen. Es soll möglich sein dass man andere klassen mit einem ähnlichen Aufgabenbereich erstelllt. Z.b. Hardware::Rs232, oder Hardware::Can, die dann von den dazugehörigen Elternklassen eingebunden werden können.

Communication_General.png

Dabei darf die Elternklasse nur bestimmte Kindklassen erben.

Ich hab auch eine Grafik mit meiner aktuellen implementierung gemacht:

Communication_Architectur.png

Das ganze wird meines wissens auch Abstrakte Fabrik genannt, ich hab aber keine Implementationen davon gefunden die für mich nutzbar sind.

Eine möglicher Aufbau eines fertigen Baumes könnte schließlich so aussehen:

Tree_example.png

Ich hoffe ihr könnt mir helfen, ich will wenn möglich keine redundante codebasis aufbauen, sondern eine flexible (Template)-Klasse die sich für navigations-Funktionen kümmert.

Hier ein codestück das zum testen der klasse gedacht ist:

C++:
SensorHandler::MainHandler TestObject;
std::cout << "Count: " << TestObject.GetItemCount() << std::endl;

Es treten danach folgende Fehlermeldungen auf:

Code:
main.cpp:27:31: Fehler: Variable ?TestObject? kann nicht als vom abstrakten Typ ?SensorHandler::MainHandler? deklariert werden
In file included from main.cpp:11:0:
../SensorHandler/include/SensorHandler.hpp:109:10: Anmerkung:   denn die folgenden virtuellen Funktionen sind rein innerhalb ?SensorHandler::MainHandler?:
In file included from main.cpp:11:0:
../SensorHandler/include/SensorHandler.hpp:35:20: Anmerkung: 	virtual void SensorHandler::Baseclass::NewItem(std::string, std::tr1::shared_ptr<SensorHandler::Baseclass>)

Wenn ich dann die Funktin NewItem deaktiviere funktioniert das compilieren. Ich schätze dass das problem an der Typenübergabe oä. liegt.

mfg, pointhi
 
Zuletzt bearbeitet von einem Moderator:
Hallo pointhi

Dein Problem ist mit den Templatetypen:
C++:
virtual void NewItem(const std::string Name, std::tr1::shared_ptr<Baseclass> Type) = 0;

das gilt es zu implementieren, in deinem Baum sieht das so aus:
C++:
virtual void NewItem(const std::string Name, std::tr1::shared_ptr<_T> Type)

_T ist der erste Templateparameter von TreeHandler. Du verwendest das so:
C++:
class MainHandler : public SensorHandler::TreeHandler<Hardware::Hardware,Baseclass>{

Also ist _T der Typ Hardware::Hardware, was aber nicht Baseclass ist. Ergo ist das eine andere Funktion. Verwende daher entweder explizit die Typenangabe Baseclass für die zu implementierenden Funktion, wenn du das ganze nämlich nur so verwenden willst wird TreeHandler da nie was anderes als Baseclass verwenden dürfen, oder aber nimm den zweiten Templateparameter:
C++:
         virtual const _Baseclass* GetItem(std::string Name) const
            {
            return this->ChieldElements.at(Name).get();
//            this->ChieldElements.at(Name);
            return NULL;
            }
         
         virtual const _Baseclass* GetItem(signed int Id) const
            {
//            return &this->ChieldElements.begin();   //openpoint todo
            return NULL;
            }
      
         virtual signed int GetItemCount( void )
            {
            return (this->ChieldElements.size());
            }
         
         virtual void NewItem(const std::string Name, std::tr1::shared_ptr<_Baseclass> Type)   // std::tr1::shared_ptr<_T> 
            {
//            this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<_T> >(Name,Type));
            }

Grüsse
Cromon
 
Ich hab jetzt nicht deine implementierung versucht, sondern mal allgemein probiert ob es ohne templates funktioniert. Und die Antwort ist nein. Irgendwie hab ich da einen schweren Fehler, den ich einfach nicht finde.

Hier meine TestImplementierung:

C++:
/* 
 * File:   SensorHandler.hpp
 * Author: pointhi
 * Licence: LGPLv3
 *
 * Created on 26. April 2013, 14:13
 */

#ifndef SENSORHANDLER_HPP
#define	SENSORHANDLER_HPP

#include <string>
#include <map>
#include <iostream>

#include <tr1/memory>

namespace SensorHandler {
   
   class Baseclass { // Basisklasse um generelle Variablen und virtuelle Funktionen zu deklarieren
   
   public:
      
      std::string Name;    // Variable, die jedes Objekt besitzt
      
      Baseclass() {this->Name = "Baseclass";}
      
      void Output() {std::cout << "Hello Name: " << this->Name << std::endl;}
      
      virtual const Baseclass* GetItem(std::string Name) const = 0;
//      virtual const Baseclass* GetItem(signed int Id) const = 0;
      
      virtual signed int GetItemCount( void ) = 0;
      
      virtual void NewItem(const std::string Name, std::tr1::shared_ptr<Baseclass> Item) = 0;  // std::tr1::shared_ptr<Baseclass> 
//      virtual void NewItem(const std::string Name) = 0;
   };
   
   
   namespace Hardware {
   
      class Hardware : public SensorHandler::Baseclass {

      };
      
      namespace I2cSlave {
         class I2cSlave : public SensorHandler::Baseclass {

         };
         
      class Slave : public I2cSlave {   // public Hardware : 
            
         private:
         
            std::map<const std::string, std::tr1::shared_ptr<I2cSlave> > ChieldElements;
         
         public:

            Slave() {this->Name = "Slave";}
            
            const I2cSlave* GetItem(std::string Name) const
               {
               return this->ChieldElements.at(Name).get();
               }

            signed int GetItemCount( void )
               {
               return (this->ChieldElements.size());
               }
            
            void NewItem(const std::string Name, std::tr1::shared_ptr<I2cSlave> Item)   // std::tr1::shared_ptr<_T> 
            {
//            this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave> >(Name,Item));
            }    
            
         };
      }
      
      class I2c : public Hardware { // SensorHandler::TreeHandler<SensorHandler::Hardware::I2c, SensorHandler::Hardware::Hardware>
         
         private:
         
         std::map<const std::string, std::tr1::shared_ptr<I2cSlave::I2cSlave> > ChieldElements;
         
         public:

            I2c() {this->Name = "I2c";}
            
            const I2cSlave::I2cSlave* GetItem(std::string Name) const
               {
               return this->ChieldElements.at(Name).get();
               }

            signed int GetItemCount( void )
               {
               return (this->ChieldElements.size());
               }
            
            void NewItem(const std::string Name, std::tr1::shared_ptr<I2cSlave::I2cSlave> Item)   // std::tr1::shared_ptr<_T> 
               {
//               this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave::I2cSlave> >(Name,Item));
               } 

      };
   }

   
   class MainHandler : public Baseclass {
      
      private:
         
         std::map<const std::string, std::tr1::shared_ptr<Hardware::Hardware> > ChieldElements;
      
      public:
         
         MainHandler() {this->Name = "MainHandler";}
      
         const Hardware::Hardware* GetItem(std::string Name) const
            {
            return this->ChieldElements.at(Name).get();
            }
         
         signed int GetItemCount( void )
            {
            return (this->ChieldElements.size());
            }
         
         void NewItem(const std::string Name, std::tr1::shared_ptr<Hardware::Hardware> Item)   // std::tr1::shared_ptr<_T> 
            {
//            this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<Hardware::Hardware> >(Name,Item));
            } 

   };
   
}

#endif	/* SENSORHANDLER_HPP */

Es kommen noch immer die gleichen Fehlermeldungen:

Code:
main.cpp:27:33: Fehler: Variable ?TestObject? kann nicht als vom abstrakten Typ ?SensorHandler::Hardware::I2c? deklariert werden
In file included from main.cpp:11:0:
../SensorHandler/include/SensorHandler.hpp:116:13: Anmerkung:   denn die folgenden virtuellen Funktionen sind rein innerhalb ?SensorHandler::Hardware::I2c?:
In file included from main.cpp:11:0:
../SensorHandler/include/SensorHandler.hpp:35:20: Anmerkung: 	virtual void SensorHandler::Baseclass::NewItem(std::string, std::tr1::shared_ptr<SensorHandler::Baseclass>)

Ich hab keine ahnung was da falsch läuft, ich hab das problem soweit eingrenzen können dass es an der Funktion NewItem liegt. Wenn diese in der Elternklasse deaktiviert ist funktioniert das ganze (aber nur im Rumpf des Baumes, darüber kann ich keine Elemente erzeugen.). Damit das ganze auch mit Elternklasse funktioniert muss der Übergabeparameter vom Typ Baseclass sein, keine davon abgeleitete Abstrakte Klasse. Das ist aber Problematisch, da dadurch die Typenüberprüfung deaktiviert ist, und so auftretene Fehler in die Laufzeit verschoben werden.

Entweder, der Fehler wird gefunden, oder ich muss den Typ als String übergeben, oder ich nutze ein anderes Modell (wobei ich nicht weiß wie es ausschauen würde.)

mfg, pointhi
 
Zuletzt bearbeitet von einem Moderator:
Hallo pointhi

std::shared_ptr<A> ist nicht das gleiche wie std::shared_ptr<B>, das hab ich dir schon oben versucht zu erklären.

void NewItem(std::shared_ptr<Ic2::Hardward::Slave>) ist NICHT void NewItem(std::shared_ptr<Baseclass>)

Das sind zwei unterschiedliche Funktionen. void foo(int) ist auch nicht die gleiche Funktion wie void foo(float).

Grüsse
Cromon
 
Mehr oder weniger schon, da Ic2::Hardward::Slave auf Baseclass aufbaut.

Ich hab es jetzt so gelöst dass ich den Namen des types als string übergebe und dann mit if-else auswerte. Wenn ich später eine bessere Lösung finde kann ich diese paralell dazu implementieren.

Ich schaue noch immer wie ich am besten die redundanz so niedrieg wie möglich halte, wobei ich derzeit aber in die andere richtung arbeite um zu schauen ob es so eigentlich richtig funktioniert.
 
Hallo pointhi

Bitte was? Slave ERBT von Baseclass, Slave IST NICHT Baseclass, das sind zwei Typen, zwei unterschiedliche Typen. Die Vererbung ist ausschliesslich eine Relation, das sind dann nicht die gleichen Typen, das sollte logisch sein. Wenn du eine Funktion in einer erbenden Klasse überschreibst muss sie identisch sein und nicht nur so ein bisschen ähnlich sein.

Ich kann nicht nachvollziehen warum dich hier so komplett auf den Kopf stellst und irgendwelchen merkwürdigen Sachen machst wie Typenübergabe als string... Alles was du machen musst ist einfach in allen erbenden Klassen die richtige Signatur verwenden. Wie gesagt, das ist die Änderung eines Parameters.

Grüsse
Cromon
 
Ich machs jetzt einfach mal mit strings, erweitern kann man es immer noch:

C++:
void NewItem(const std::string Name, const std::string Item)   // std::tr1::shared_ptr<_T> 
            {
            
            if(Item == "I2C")
               {
               this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<Hardware::Hardware> >(Name,std::tr1::shared_ptr<Hardware::Hardware>(new Hardware::I2c)));
               }
            else
               {
               throw 1;
               }
            }

Wie man sieht erstelle ich ein Objekt vom Typ Hardware::I2C und lade es in einen Datencontainer vom Typ Hardware::Hardware, der zufälligerweise auch die Elternklasse von Hardware::I2C ist.
Das solche Relationen funktionieren habe ich schon bewießen, man muss nur bedenken dass keine ganzen Variablen sondern nur Pointer übergeben werden düfen, da die Größe der Typen Variieren kann. So konnte ich erfolgreich unterschiedliche Typen mittels Funktionen zurückgeben, nur übergeben kann ich solche Typen bisher nicht. (Auch nicht als Pointer)

Hier mal ein kleines Testprogramm das "komischerweise" funktioniert:

C++:
SensorHandler::MainHandler TestObject;
   std::cout << "Count: " << TestObject.GetItemCount() << std::endl;

   TestObject.NewItem("Test1","I2C");
   std::cout << "Count: " << TestObject.GetItemCount() << std::endl;
   
   TestObject.NewItem("Test2","I2C");
   std::cout << "Count: " << TestObject.GetItemCount() << std::endl;
   
   std::cout << "Name, Test1: " << TestObject.GetItem("Test1")->Name << std::endl;
   
   std::cout << "Count, Test1: " << TestObject.GetItem("Test1")->GetItemCount() << std::endl;
   
   TestObject.GetItem("Test1")->NewItem("Slave1","SLAVE");
   
   std::cout << "Count, Test1: " << TestObject.GetItem("Test1")->GetItemCount() << std::endl;
   
   std::cout << "Name, Slave1: " << TestObject.GetItem("Test1")->GetItem("Slave1")->Name << std::endl;

Die Ausgabe ist wie folgt:

C++:
Count: 0
Count: 1
Count: 2
Name, Test1: I2c
Count, Test1: 0
Count, Test1: 1
Name, Slave1: Slave

mfg, pointhi
 
Zuletzt bearbeitet von einem Moderator:
Hallo pointhi

Entschuldige die Wahl meiner Worte, aber das eine grauenhafte Lösung, bzw gar keine Lösung! Ich verstehe nicht was so wahnsinnig schwer daran ist zu verstehen, dass du bei NewItem nicht std::shared_ptr<I2CSlave> schreiben musst sondern std::shared_ptr<Baseclass>. Mir ist schon klar, dass du die Typen limitieren willst, aber dazu gibt es bereits vorgefertigte Methoden.

Hier siehst du wie das machen kannst damit du nicht Stringvergleiche machen musst:
C++:
            void NewItem(const std::string Name, std::tr1::shared_ptr<Baseclass> Item)
               {
				   std::shared_ptr<I2cSlave::I2cSlave> slavePtr = std::dynamic_pointer_cast<I2cSlave::I2cSlave>(Item);
//               this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave::I2cSlave> >(Name,Item));
               }

slavePtr ist nullptr, wenn Item nicht ein ein I2cSlave ist.

Grundsätzlich finde ich aber sowieso, dass das ein Designfehler ist. Du definierst NewItem als eine Eigenschaft aller Handler mit Baseclass, das ist es aber nicht! Ganz offenbar akzeptieren die Kindklassen nicht alle std::shared_ptr<Baseclass>, also hat das auch nichts in der abstrakten Vaterklasse zu suchen. Allgemein sind deine Abhängigkeiten und Vererbungen sehr undurchsichtig und kaum nachvollziehbar, ich würde dir da vorschlagen deine Diagramme und Modelle, die du erstellt hast nochmals zu konsultieren und zu überlegen, ob das wirklich glücklich gewählt ist.

Dein Testprogramm kann übrigens mit dem im ersten Posting geposteten Code auf Strings angepasst nicht funktionieren, schon alleine wegen dieser Zeile:
C++:
TestObject.GetItem("Test1")->NewItem("Slave1","SLAVE");

GetItem gibt dir ein const Item zurück, NewItem ist alles andere als const.

So wie du es aktuell hast ist die einzige vernünftige Designentscheidung Baseclass als Template zu machen, weil Baseclass für verschiedene Kindklassen unterschiedlich aussieht und auch ein anderes Interface darstellen muss.

C++:
namespace SensorHandler {
   
   template<typename T>
   class Baseclass { // Basisklasse um generelle Variablen und virtuelle Funktionen zu deklarieren
   
   public:
      
      std::string Name;    // Variable, die jedes Objekt besitzt
      
      Baseclass() {this->Name = "Baseclass";}
      
      void Output() {std::cout << "Hello Name: " << this->Name << std::endl;}
      
      virtual T* GetItem(std::string Name) const = 0;
//      virtual const Baseclass* GetItem(signed int Id) const = 0;
      
      virtual signed int GetItemCount( void ) const = 0;
      
      virtual void NewItem(const std::string Name, std::tr1::shared_ptr<T> Item) = 0;  // std::tr1::shared_ptr<Baseclass> 
//      virtual void NewItem(const std::string Name) = 0;
   };
   
   
   namespace Hardware {
      namespace I2cSlave {
         class I2cSlave : public SensorHandler::Baseclass<I2cSlave> {
 
         };
         
      class Slave : public I2cSlave {   // public Hardware : 
            
         private:
         
            std::map<const std::string, std::tr1::shared_ptr<I2cSlave> > ChieldElements;
         
         public:
 
            Slave() {this->Name = "Slave";}
            
            I2cSlave* GetItem(std::string Name) const
               {
               return this->ChieldElements.at(Name).get();
               }
 
            signed int GetItemCount( void ) const
               {
               return (this->ChieldElements.size());
               }
            
            void NewItem(const std::string Name, std::tr1::shared_ptr<I2cSlave> Item)   // std::tr1::shared_ptr<_T> 
            {
            this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave> >(Name,Item));
            }    
            
         };
      }

	  class Hardware : public SensorHandler::Baseclass<I2cSlave::I2cSlave> {
 
      };
      
      class I2c : public Hardware { // SensorHandler::TreeHandler<SensorHandler::Hardware::I2c, SensorHandler::Hardware::Hardware>
         
         private:
         
         std::map<const std::string, std::tr1::shared_ptr<I2cSlave::I2cSlave> > ChieldElements;
         
         public:
 
            I2c() {this->Name = "I2c";}
            
            I2cSlave::I2cSlave* GetItem(std::string Name) const
               {
               return this->ChieldElements.at(Name).get();
               }
 
            signed int GetItemCount( void ) const
               {
               return (this->ChieldElements.size());
               }
            
            void NewItem(const std::string Name, std::shared_ptr<I2cSlave::I2cSlave> Item)
               {
               this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave::I2cSlave> >(Name,Item));
               } 
 
      };
   }
 
   
   class MainHandler : public Baseclass<Hardware::Hardware> {
      
      private:
         
         std::map<const std::string, std::tr1::shared_ptr<Hardware::Hardware> > ChieldElements;
      
      public:
         
         MainHandler() {this->Name = "MainHandler";}
      
         Hardware::Hardware* GetItem(std::string Name) const
            {
            return this->ChieldElements.at(Name).get();
            }
         
         signed int GetItemCount( void ) const
            {
            return (this->ChieldElements.size());
            }
         
         void NewItem(const std::string Name, std::tr1::shared_ptr<Hardware::Hardware> Item)   // std::tr1::shared_ptr<_T> 
            {
            this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<Hardware::Hardware> >(Name,Item));
            } 
 
   };
   
}

Ich weiss, du wirst wohl wieder die Antwort einfach ignorieren und weiterhin mit strings als Typenparameter arbeiten, in dem Fall hoff ich einfach, dass das nicht Produktivcode einer grösseren Anwendung wird.

Grüsse
Cromon
 
Ich werde mir es mal anschauen, ich hab bisher nichts vom übergeben der Baseclass gehalten da dadurch ja auch ungültige Typen übergeben werden können.

GetItem gibt dir ein const Item zurück, NewItem ist alles andere als const.
Hab ich auch herausgefunden, hab das ja auch geändert. Nur hab ich es nicht gepostet, weil es derzeitig nebensächlich ist.

Wegen dem Aufbau, es ist der für mich derzeit schlüssigste und beste Aufbau den ich gefunden habe. Es ist ja nicht der erste Versuch dieses Aufbaues.

Ich hab es mal implementiert:

C++:
/* 
 * File:   SensorHandler.hpp
 * Author: pointhi
 * Licence: LGPLv3
 *
 * Created on 26. April 2013, 14:13
 */

#ifndef SENSORHANDLER_HPP
#define	SENSORHANDLER_HPP

#include <string>
#include <map>
#include <iostream>

#include <tr1/memory>

namespace SensorHandler {
   
   class Baseclass { // Basisklasse um generelle Variablen und virtuelle Funktionen zu deklarieren
   
   public:
      
      std::string Name;    // Variable, die jedes Objekt besitzt
      
      Baseclass() {this->Name = "Baseclass";}
      
      void Output() {std::cout << "Hello Name: " << this->Name << std::endl;}
      
      virtual Baseclass* GetItem(std::string Name) const = 0;
      virtual Baseclass* GetItem(signed int Id) const = 0;
      
      virtual signed int GetItemCount( void ) = 0;
      
//      virtual void NewItem(const std::string Name, const std::string Item) = 0;  // std::tr1::shared_ptr<Baseclass> 
      void NewItem(const std::string Name, std::tr1::shared_ptr<Baseclass> Item);
//      virtual void NewItem(const std::string Name) = 0;
   };
   
//   template<typename _T, typename _Baseclass = Baseclass>   // , Baseclass _CLASS
//   class TreeHandler : public _Baseclass {  //  : public Baseclass
//      
//      private:
//      
//         std::map<const std::string, std::tr1::shared_ptr<_T> > ChieldElements;  // std::tr1::shared_ptr<_T>
//         
//      public:
//      
//         TreeHandler()
//            {
//            }
//         
//         virtual const _T* GetItem(std::string Name) const
//            {
//            return this->ChieldElements.at(Name).get();
////            return this->ChieldElements.at(Name);
//            return NULL;
//            }
//         
//         virtual const _T* GetItem(signed int Id) const
//            {
////            return &this->ChieldElements.begin();   //openpoint todo
//            return NULL;
//            }
//      
//         virtual signed int GetItemCount( void )
//            {
//            return (this->ChieldElements.size());
//            }
//         
//         virtual void NewItem(const std::string Name, std::tr1::shared_ptr<_T> Item)   // std::tr1::shared_ptr<_T> 
//            {
////            this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<_T> >(Name,Item));
//            }    
//   
//   };
   
   namespace Hardware {
   
      class Hardware : public SensorHandler::Baseclass {

      };
      
      namespace I2cSlave {
         class I2cSlave : public SensorHandler::Baseclass {

         };
         
      class Slave : public I2cSlave {   // public Hardware : 
            
         private:
         
            std::map<const std::string, std::tr1::shared_ptr<I2cSlave> > ChieldElements;
         
         public:

            Slave() {this->Name = "Slave";}
            
            I2cSlave* GetItem(std::string Name) const
               {
               return this->ChieldElements.at(Name).get();
               }

            I2cSlave* GetItem(signed int Id) const
               {
//               std::map<const std::string, std::tr1::shared_ptr<I2cSlave>::iterator ChieldElementsIterator=ChieldElements.begin();
//             ChieldElementsIterator ++;
//               return ChieldElementsIterator->second->get();
               return NULL;   // openpoint todo
               }
            
            signed int GetItemCount( void )
               {
               return (this->ChieldElements.size());
               }
            
//            void NewItem(const std::string Name, const std::string Item)   // std::tr1::shared_ptr<_T> 
//               {
//                  throw 1;
//               } 
            
               void NewItem(const std::string Name, std::tr1::shared_ptr<Baseclass> Item)
                  {
                  std::tr1::shared_ptr<I2cSlave> slavePtr = std::tr1::dynamic_pointer_cast<I2cSlave>(Item);
                  if(slavePtr != NULL)
                     {
//                     this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave> >(Name,slavePtr));
                     }
                  }
            
         };
      }
      
      class I2c : public Hardware { // SensorHandler::TreeHandler<SensorHandler::Hardware::I2c, SensorHandler::Hardware::Hardware>
         
         private:
         
         std::map<const std::string, std::tr1::shared_ptr<I2cSlave::I2cSlave> > ChieldElements;
         
         public:

            I2c() {this->Name = "I2c";}
            
            I2cSlave::I2cSlave* GetItem(std::string Name) const 
               {
               return this->ChieldElements.at(Name).get();
               }

            I2cSlave::I2cSlave* GetItem(signed int Id) const
               {
//               std::map<const std::string, std::tr1::shared_ptr<I2cSlave::I2cSlave>::iterator ChieldElementsIterator=ChieldElements.begin();
//             ChieldElementsIterator ++;
//               return ChieldElementsIterator->second->get();
               return NULL;   // openpoint todo
               }
            
            signed int GetItemCount( void )
               {
               return (this->ChieldElements.size());
               }
            
//            void NewItem(const std::string Name, const std::string Item)   // std::tr1::shared_ptr<_T> 
//               {
//
//               if(Item == "SLAVE")
//                  {
//                  this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave::I2cSlave> >(Name,std::tr1::shared_ptr<I2cSlave::I2cSlave>(new I2cSlave::Slave)));
//                  }
//               else
//                  {
//                  throw 1;
//                  }
//               } 
            
            void NewItem(const std::string Name, std::tr1::shared_ptr<Baseclass> Item)
               {
               std::tr1::shared_ptr<I2cSlave::I2cSlave> slavePtr = std::tr1::dynamic_pointer_cast<I2cSlave::I2cSlave>(Item);
               if(slavePtr != NULL)
                  {
                  this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<I2cSlave::I2cSlave> >(Name,slavePtr));
                  }
               }

      };
   }

   
   class MainHandler : public Baseclass {
      
      private:
         
         std::map<const std::string, std::tr1::shared_ptr<Hardware::Hardware> > ChieldElements;
         std::map<const std::string, std::tr1::shared_ptr<Hardware::Hardware> >::const_iterator ChieldElementsIterator;
      
      public:
         
         MainHandler() {this->Name = "MainHandler";}
      
         Hardware::Hardware* GetItem(std::string Name) const
            {
            return this->ChieldElements.at(Name).get();
            }
         
         Hardware::Hardware* GetItem(signed int Id) const
            {
            
            int i=0;
//            ChieldElementsIterator.(this->ChieldElements.begin());
            
//            ChieldElementsIterator = this->ChieldElements.begin(); // openpoint todo
            
            for(;i<Id && ChieldElementsIterator!=this->ChieldElements.end();i++)
               {
//               ChieldElementsIterator ++;
               }
            
            if(i == Id && this->ChieldElements.size() != 0)
               {
               return ChieldElementsIterator->second.get(); // openpoint todo
               }
            else
               {
               throw 1; // openpoint todo
               return NULL;
               }
            }
         
         signed int GetItemCount( void )
            {
            return (this->ChieldElements.size());
            }
         
//         void NewItem(const std::string Name, const std::string Item)   // std::tr1::shared_ptr<_T> 
//            {
//            
//            if(Item == "I2C")
//               {
//               this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<Hardware::Hardware> >(Name,std::tr1::shared_ptr<Hardware::Hardware>(new Hardware::I2c)));
//               }
//            else
//               {
//               throw 1;
//               }
//            }
         
         void NewItem(const std::string Name, std::tr1::shared_ptr<Baseclass> Item)
               {
               std::tr1::shared_ptr<Hardware::Hardware> slavePtr = std::tr1::dynamic_pointer_cast<Hardware::Hardware>(Item);
               if(slavePtr != NULL)
                  {
                  this->ChieldElements.insert(std::pair<const std::string,std::tr1::shared_ptr<Hardware::Hardware> >(Name,slavePtr));
                  }
               }

   };
   
}

#endif	/* SENSORHANDLER_HPP */

Es funktioniert teilweise:

C++:
SensorHandler::MainHandler TestObject;
   std::cout << "Count: " << TestObject.GetItemCount() << std::endl;

   TestObject.NewItem("NewTest1",std::tr1::shared_ptr<SensorHandler::Hardware::Hardware>(new SensorHandler::Hardware::I2c));
   std::cout << "Count: " << TestObject.GetItemCount() << std::endl;
   
   TestObject.NewItem("NewTest2",std::tr1::shared_ptr<SensorHandler::Hardware::I2cSlave::I2cSlave>(new SensorHandler::Hardware::I2cSlave::Slave));  // test wegen fehlererkennung
   std::cout << "Count: " << TestObject.GetItemCount() << std::endl;
   
   std::cout << "Name, NewTest1: " << TestObject.GetItem("NewTest1")->Name << std::endl;
   
   std::cout << "Count, NewTest1: " << TestObject.GetItem("NewTest1")->GetItemCount() << std::endl;
   
   //TestObject.GetItem("NewTest1")->NewItem("Slave1",std::tr1::shared_ptr<SensorHandler::Hardware::I2cSlave::I2cSlave>(new SensorHandler::Hardware::I2cSlave::Slave));
   
   std::cout << "Count, NewTest1: " << TestObject.GetItem("NewTest1")->GetItemCount() << std::endl;
   
   std::cout << "Name, Slave1: " << TestObject.GetItem("NewTest1")->GetItem("Slave1")->Name << std::endl;

Ergibt folgende Ausgabe:

C++:
Count: 0
Count: 1
Count: 1
Name, NewTest1: I2c
Count, NewTest1: 0
Count, NewTest1: 0

Mal davon abgesehen dass das Programm abstürtzt weil Slave1 nicht exestiert, die auskommentierte Zeile:

C++:
TestObject.GetItem("NewTest1")->NewItem("Slave1",std::tr1::shared_ptr<SensorHandler::Hardware::I2cSlave::I2cSlave>(new SensorHandler::Hardware::I2cSlave::Slave));

erzeugt folgenden Fehler wenn ich sie aktiviere:

Code:
C:\Users\thomas\informatik\c++\SensorHandlerTest/main.cpp:40: undefined reference to `SensorHandler::Baseclass::NewItem(std::string, std::tr1::shared_ptr<SensorHandler::Baseclass>)'

Ich hab den Fehler davon nicht gefunden.

Wenn ich Baseclass als Template implementiere sehe ich das problem dass der Compiler nicht mehr wissen kann, ob der zurückgegebene Pointer von GetItem wieder auf ein Objekt vom Typ Baseclass verweist, und ob deshalt die benötigten Funktionen enthalten sind. Dadurch wäre es nicht mehr möglich einfach im Baum elemente auszulesen, sondern nur mehr die Klasse auf ihre Kindelemente.

Was ich wichtiger finde wäre eine saubere implementierung der ganzen virtuellen Funktonen in ein Template, um die ganze redundanz zu verhindern. Ob das Template vom Anfang so gut dazu taugt wie ich will ist für mich derzeit noch unklar

mfg, pointhi
 
Zuletzt bearbeitet von einem Moderator:
Zurück