polymorphie



  • Ich brauche eine Klasse, die mir Zufallszahlen nach versch. Algorithmen und Verteilungen gibt - und muss sie noch in nem Array speichern können - allerdings gestaltet sich das Ändern der Verteilung/des Algorithmus schwerer, als ich das zunächst annahm -.- Und man kann so ne Aufgaben ja auch nich ewig vor sich herschieben ^^

    Die Zufallszahlen-Klasse an sich:

    struct TRandom_Base
    {
    	typedef size_t result_type;
    	typedef result_type multiplicator;
    
    	virtual ~TRandom_Base() {}
    
    	virtual result_type operator() (multiplicator) = 0;
    };
    
    template <typename Tengine = Random::Engine::MersenneTwister19937, typename Tdistribution = Random::Distribution::uniform_real>
    class TRandom : public TRandom_Base
    {
    public:
    	typedef boost::variate_generator <Tengine, Tdistribution> Tgenerator;
    private:
    	Tengine engine;
    	Tgenerator generator;
    public:
    	TRandom (boost::uint32_t seed)
    		: engine ( seed ), generator ( engine, Tdistribution (0, 1) )
    	{}
    
    	//get a value from the interval [0, multiply)
    	result_type operator () (multiplicator multiply)
    	{
    		return result_type ( generator() * multiply );
    	}
    };
    

    Und dann dachte ich mir, nehm ich das Factory-Pattern und bau dort das Ändern ein:

    struct TRandom_Factory : my::Singleton <TRandom_Factory>
    {
    	TRandom_Factory() {}
    
    	TRandom_Base* Create()
    	{
    		return new TRandom <> (0);
    	}
    
    	void Destruct (TRandom_Base* value)
    	{
    		delete value;
    	}
    
    	void SetAlgorithm (const std::string &algorithm, TRandom_Base *& these)
    	{
    		TRandom_Base* toswap = nullptr;
    		if (algorithm == Random::Engine::Name::MersenneTwister19937)
    		{
    			toswap = new TRandom <Random::Engine::MersenneTwister19937, /*...1...*/> (123);
    		}
    		else if (algorithm == /**/)
    		{
    			//;
    		}
    		else
    		{
    			throw std::invalid_argument ("TRandom_Factory::SetAlgo=" + algorithm);
    		}
    
    		std::swap (toswap, these);
    		Destruct (toswap);
    	}
    };
    

    allerdings weiß ich nicht, wie ich aus der basis-klasse die verteilung bekommen soll, die ich dann (wieder) nehme (siehe ...1...).
    Oder würdet ihr das alles vll ganz anders machen?

    bb



  • *push*
    ja ich weiß, so was macht man nicht... aber ich wills doch trotzdem wissen 😛



  • Muss das so kompliziert sein? Warum brauchst du ne Factory? Warum müssen die ne gemeinsame Basisklasse haben?



  • weil ich sie in nem anderen objekt natürlich brauche, weil ich dort die zufallszahlen brauche, also brauch ich ne polymorphe basisklasse - die factory is keine pflicht, aber ich denke, mit kann man es besser kapseln...

    bb


  • Administrator

    1. Das mit der Factory, so wie du es jetzt hast, wird nicht funktionieren. Es ist erst zur Laufzeit bekannt, auf was für ein Objekt these zeigt. Templateparameter müssen aber zur Kompilezeit bekannt sein.

    2. Deine TRandom Klasse ist ein ziemlicher Unsinn oder sagen wir mal, wird nicht alle Kombinationen aufnehmen können. Da fehlen noch eine Menge an Spezialisierungen. Schau dir mal die verschiedenen Engines an, die haben nicht alle Seed Möglichkeiten und zum Teil erwarten sie unterschiedliche Typen. Die Distributionen unterscheiden sich auch und haben nicht alle die gleichen Konstruktoren.

    3. Eine allgemeine Lösung sehe ich nicht.
    Wenn du die Auswahl an Engines und Distributionen einschränkst und für Gemeinsamkeiten in dieser Einschränkung sorgst, dann könntest du vielleicht eine Basisklasse für die Engines und eine Basisklasse für die Distributionen erstellen. Danach könntest du eine std::map<std::string, BaseEngine*> und eine std::map<std::string, BaseDistribution*> machen. Kannst statt std::string auch einen int oder sowas nehmen. So könntest du dann durch IDs dein Objekt zusammenbauen. Der Wechsel von einer Distribution oder einer Engine ist dann natürlich einfach, da man nur einen Zeiger ersetzen kann.

    Grüssli



  • Dravere schrieb:

    1. Das mit der Factory, so wie du es jetzt hast, wird nicht funktionieren. Es ist erst zur Laufzeit bekannt, auf was für ein Objekt these zeigt. Templateparameter müssen aber zur Kompilezeit bekannt sein.

    Ist mir schon klar, dass es so nicht funktioniert - aber für sowas gibts ja immer workarounds (z.bsp. enums) ^^

    Dravere schrieb:

    2. Deine TRandom Klasse ist ein ziemlicher Unsinn oder sagen wir mal, wird nicht alle Kombinationen aufnehmen können. Da fehlen noch eine Menge an Spezialisierungen. Schau dir mal die verschiedenen Engines an, die haben nicht alle Seed Möglichkeiten und zum Teil erwarten sie unterschiedliche Typen. Die Distributionen unterscheiden sich auch und haben nicht alle die gleichen Konstruktoren.

    Jopp - aber dann würden halt nur die gehen, die die gleichen ctor`s haben - und den seed kann ich zur not noch casten - wenn sie kein seed unterstützen, sind sie eh unbrauchbar...
    Und wenn nicht alle gehen, dann gehen eben nur nen paar - ist (in meinen Augen) eh nen ziemlich sinnfreies feature... ^^

    Dravere schrieb:

    3. Eine allgemeine Lösung sehe ich nicht.
    Wenn du die Auswahl an Engines und Distributionen einschränkst und für Gemeinsamkeiten in dieser Einschränkung sorgst, dann könntest du vielleicht eine Basisklasse für die Engines und eine Basisklasse für die Distributionen erstellen. Danach könntest du eine std::map<std::string, BaseEngine*> und eine std::map<std::string, BaseDistribution*> machen. Kannst statt std::string auch einen int oder sowas nehmen. So könntest du dann durch IDs dein Objekt zusammenbauen. Der Wechsel von einer Distribution oder einer Engine ist dann natürlich einfach, da man nur einen Zeiger ersetzen kann.

    das würde zwar gehen, aber man würde sich das zufallszahlen-objekt ja kaputt machen, weil mehrere klassen sich das gleiche teilen und somit beeinflussen sie ja beide den aktuellen zustand (seed) des generators - deshalb hatte ich die idee ziemlich schnell wieder verworfen... oder hast du dafür noch ne idee?

    bb



  • unskilled schrieb:

    das würde zwar gehen, aber man würde sich das zufallszahlen-objekt ja kaputt machen, weil mehrere klassen sich das gleiche teilen und somit beeinflussen sie ja beide den aktuellen zustand (seed) des generators - deshalb hatte ich die idee ziemlich schnell wieder verworfen... oder hast du dafür noch ne idee?

    Ich verstehs immer noch nicht. Ich dachte, dass du das willst. Was sollen das ganze eigentlich am Schluss können?



  • ok - da es mit viel text offensichtlich nicht klappt, dann halt mal so...

    ich will am ende sowas können:

    class Tverkaeufer
    {
     TRandom_Base *nachfrage;
     size_t ware;
     size_t max;
    
     void SimulatePeriod()
     {
       ware -= nachfrage->operator () ( max );
     }
    };
    

    es gibt mehrere verkäufer, also brauch ich noch nen vector:
    std::vector <Tverkaeufer> verkaeufer

    und jetzt möchte ich so etwas können:

    verkaeufer[123].SetMaxNachfrage(20);
    //und:
    verkauefer[123].SetAlgorithmus( MERSENNE_TWISTER );
    //und vor allem:
    verkauefer[123].SetVerteilung( EXPOTENTIAL );
    

    das solls aber noch nicht gewesen sein:

    {
      std::ifstream save ("save.txt");
      verkauefer[123].SaveSeed(save);
      verkaeufer[123].SetSeed(123456);
    }
    
    {
      std::ofstream load ("save.txt");
      verkaeufer[12].LoadFrom (load);
    }
    

    besser?

    bb


  • Administrator

    Wer sagt, dass du für die gleiche ID immer das gleiche Objekt zurückgeben musst? Du kannst immer ein neues Objekt vom Typ erstellen, welcher die ID angibt. Eine clone() Methode in den Basisklassen von den Engines und Distributionen ist da sicherlich hilfreich.

    Aber mir ist es sowieso ein wenig ein Rätsel, was du damit erreichen willst. Wieso willst du unterschiedliche Distributionen, wieso unterschiedliche Engines? Meistens entscheidet man sich für die beste Lösung für den entsprechenden Zweck und wechselt nicht die Generatoren zur Laufzeit.

    Grüssli



  • Dravere schrieb:

    Meistens entscheidet man sich für die beste Lösung für den entsprechenden Zweck und wechselt nicht die Generatoren zur Laufzeit.

    Hab ich meinem Prof. auch erklären wollen, aber er wollte dies nun mal können und dann hab ich gesagt: "ich guck mal - vll bekomm ich es ja iwie hin"...
    Sein Argument (was nicht ganz von der hand zu weisen ist,) war: "[Zu versch. Zeitintervallen in verschiedenen Orten können die Nachfragen ja auch unterschiedlich verteilt sein]"

    hmm.. ok - das mit dem unterschiedlichen typen klingt ganz gut - hatte ich noch gar nicht so richtig bedacht - aber klingt echt toll, danke 🙂

    ma gucken, ob ich das wirklich noch implementiere - im moment hab ich da eigtl nich so die lust - is ewig viel zu tippen und sau schwer zu testen -.-

    bb



  • Warum hängt SetAlgorithmus usw. am Verkäufer? Mach doch ein getRandom(). Irgendwie kommt mir das immer noch viel zu kompliziert gedacht vor. Und wenn Algorithmus, Verteilung usw. Parameter sein sollen, dann würde ich nur eine Random Klasse machen und keine Basis Klasse mit Unterschiedlichen implementierungen.



  • mal ehrlich schrieb:

    Warum hängt SetAlgorithmus usw. am Verkäufer? Mach doch ein getRandom().

    Na klar kann ich ein getRandom machen - aber Pseudozufallszahlen sind nich zustandslos - es braucht eine Klasse, weil es sonst unmöglich wäre, bestimmte Zustände zu speichern - und vor allem wäre es nicht möglich, genau die gleichen Nachfragen bei einem Lauf mit anderen Parametern zu bekommen... Oder hab ich dich jz missverstanden?

    mal ehrlich schrieb:

    Irgendwie kommt mir das immer noch viel zu kompliziert gedacht vor. Und wenn Algorithmus, Verteilung usw. Parameter sein sollen, dann würde ich nur eine Random Klasse machen und keine Basis Klasse mit Unterschiedlichen implementierungen.

    Wie soll das denn so gehen, dass ich trotzdem noch boost verwenden kann? Ich hatte keinen Weg gefunden... Aber ich lass mich gern eines besseres belehren...

    bb



  • unskilled schrieb:

    mal ehrlich schrieb:

    Warum hängt SetAlgorithmus usw. am Verkäufer? Mach doch ein getRandom().

    Na klar kann ich ein getRandom machen - aber Pseudozufallszahlen sind nich zustandslos - es braucht eine Klasse, weil es sonst unmöglich wäre, bestimmte Zustände zu speichern - und vor allem wäre es nicht möglich, genau die gleichen Nachfragen bei einem Lauf mit anderen Parametern zu bekommen... Oder hab ich dich jz missverstanden?

    Ich glaub schon. Das getRandom gibt dir eine Zufallszahlenklasse zurück und die hat dann SetAlgorithmus.

    mal ehrlich schrieb:

    Irgendwie kommt mir das immer noch viel zu kompliziert gedacht vor. Und wenn Algorithmus, Verteilung usw. Parameter sein sollen, dann würde ich nur eine Random Klasse machen und keine Basis Klasse mit Unterschiedlichen implementierungen.

    Wie soll das denn so gehen, dass ich trotzdem noch boost verwenden kann? Ich hatte keinen Weg gefunden... Aber ich lass mich gern eines besseres belehren...

    bb

    Vielleicht wäre es ganz gut gewesen, wenn du dass von Anfang an geschrieben hättest. Irgendwie gehst du davon aus, dass alle Leute bereits wissen was du machen musst, ohne es jemals zu sagen.



  • mal ehrlich schrieb:

    unskilled schrieb:

    mal ehrlich schrieb:

    Warum hängt SetAlgorithmus usw. am Verkäufer? Mach doch ein getRandom().

    Na klar kann ich ein getRandom machen - aber Pseudozufallszahlen sind nich zustandslos - es braucht eine Klasse, weil es sonst unmöglich wäre, bestimmte Zustände zu speichern - und vor allem wäre es nicht möglich, genau die gleichen Nachfragen bei einem Lauf mit anderen Parametern zu bekommen... Oder hab ich dich jz missverstanden?

    Ich glaub schon. Das getRandom gibt dir eine Zufallszahlenklasse zurück und die hat dann SetAlgorithmus.

    Und für sowas bräuchte ich wieder ne basisklasse mit virtuellen fkt?!

    mal ehrlich schrieb:

    unskilled schrieb:

    mal ehrlich schrieb:

    Irgendwie kommt mir das immer noch viel zu kompliziert gedacht vor. Und wenn Algorithmus, Verteilung usw. Parameter sein sollen, dann würde ich nur eine Random Klasse machen und keine Basis Klasse mit Unterschiedlichen implementierungen.

    Wie soll das denn so gehen, dass ich trotzdem noch boost verwenden kann? Ich hatte keinen Weg gefunden... Aber ich lass mich gern eines besseres belehren...

    bb

    Vielleicht wäre es ganz gut gewesen, wenn du dass von Anfang an geschrieben hättest. Irgendwie gehst du davon aus, dass alle Leute bereits wissen was du machen musst, ohne es jemals zu sagen.

    hmm... sry - dachte eigtl, dass das klar ist, dass ich die funktionalität, die bereits vorhanden ist, nutzen möchte und es nicht neu schreiben will... mein fehler 🙄

    aber ist jz auch egal - hab ihm geschrieben, dass es nicht so ohne weiteres geht und ich das erst mal weglasse ^^
    aber danke nochmal 🙂

    bb


Anmelden zum Antworten