Zufallszahl generieren, aber wie?
-
Wenn man aber erst mal einige Jahre Erfahrung hat, alle Regeln und Idiome verinnerlicht hat, seinen Stil entwickelt hat ist C++ alles andere als unsicher, eben weil man genau weiss was man da macht. Ich glaube ich habe schon ewig kein explizites delete irgendwo hingeschrieben. Und wenn mal was sehr optimiertes benötigt oder sich mit einer C Biblitothek rumschlagen muss, wird jede Ekligkeit in eine Klasse gekabselt und Ruhe.
Das Problem ist, dass "gutes" Programmieren meist erst in fortgeschrittener Literatur behandelt wird, obwohl diese Dinge für Anfänger viel wichtiger sind.
-
Volle Zustimmung, brotbernd.

Leider ist der Markt auch heute noch überschwemmt von Büchern, die mit
char*-Frickeleien beginnen und einen solchen Stil angewöhnen. Kein Wunder denken immer noch so viele Leute, dass man sich in C++ wahnsinnige Mühe für grundlegende Dinge wie Speicherverwaltung oder Stringverarbeitung machen müsse.
-
Also ich lese gerade den C++ Primer Plus.
Der enthält schon solche Dinge wie char *. Im Moment kämpfe ich mich gerade durch das Kapitel "Memory Models and namespaces". Ist etwas mühsam, aber ich freue mich auf das Kapitel "Objects and Classes"

-
icarus2 schrieb:
Also ich lese gerade den C++ Primer Plus. Der enthält schon solche Dinge wie char *.
Das ist überhaupt kein Problem, der Primer gehört auch zur guten Anfängerliteratur. Natürlich darf man schon wissen, dass es
char-Arrays gibt und man damit Strings verwalten kann. Es schadet auch nicht, es anwenden zu können. Aber wenn einem von Anfang an ausschliesslich solche Dinge gezeigt werden, sodass man effektiv das Gefühl bekommt, die Sprache ermögliche keine besseren Wege, ist das etwas anderes.
-
Wie sieht es bei C++ eigentlich mit naming convetions aus?
Ich habe schon verschiedenes gelesen. camel_case, camelCase und noch anderes. Im Primer steht, es gibt verschiedene Dinge. Gibt es aktuelle naming conventions für C++ oder nicht?
-
icarus2 schrieb:
Ich habe schon verschiedenes gelesen. camel_case, camelCase und noch anderes. Im Primer steht, es gibt verschiedene Dinge. Gibt es aktuelle naming conventions für C++ oder nicht?
Es gibt verschiedene Namenskonventionen in C++.
Die Standardbibliothek und Boost verwenden
unter_striche, aber selbst bist du frei. Sei einfach einheitlich, mindestens innerhalb eines Projekts.
-
So, ich habs hinbekommen... alles funktioniert

Ich habe es so gelöst:
Ich habe alles in dem geposteten Link gelesen und anschliessend diese Klasse hier übernommen:
//Datei: random.cpp #ifndef _RANDOM_H #define _RANDOM_H #include <cstdlib> #include <ctime> #include <cassert> class Random { private: Random() { std::srand(static_cast<int>(std::time(NULL))); } public: static int rnd(int lowerbounds, int upperbounds) { static Random dummy; assert(upperbounds - lowerbounds < RAND_MAX); return lowerbounds + std::rand() % (upperbounds - lowerbounds + 1); } }; #endifDas hier ist anschliessend das file, von dem aus das Prog gestartet wird:
#include <iostream> #include <cmath> #include "random.cpp" int get_random_car_door(); int get_random_player_choice(); int get_opened_door(int car_door, int chosen_door); int get_changed_door(int opened_door, int chosen_door); double round(double number, int places); static const int Amount_of_doors = 3; int main() { using std::cin; using std::cout; using std::endl; int games; cout << "Enter the amount of games the computer shall simulate: "; cin >> games; cout << endl << endl; int wins = 0; int losses = 0; int car_door; int chosen_door; int opened_door; for(int i = 0; i < games; i++){ car_door = get_random_car_door(); chosen_door = get_random_player_choice(); opened_door = get_opened_door(car_door, chosen_door); chosen_door = get_changed_door(opened_door, chosen_door); if(chosen_door = car_door){ wins++; } else { losses++; } } double ratio = (float)wins / (float)losses; ratio = round(ratio, 3); cout << "Wins: " << wins << endl; cout << "Losses: " << losses << endl; cout << "Ratio: " << wins << " / " << losses << " = " << ratio << " : 1" << endl; int exit; cin >> exit; return 0; } int get_random_car_door(){ return Random::rnd(0, Amount_of_doors - 1); } int get_random_player_choice() { return Random::rnd(0, Amount_of_doors - 1); } int get_opened_door(int car_door, int chosen_door){ int opened_door; while(true){ opened_door = Random::rnd(0, Amount_of_doors - 1); if(opened_door != car_door && opened_door != chosen_door){ return opened_door; } } } int get_changed_door(int opened_door, int chosen_door){ for(int i = 0; i < Amount_of_doors; i++){ if(i != opened_door && i != chosen_door){ return i; } } } double round(double number, const int places){ int factor = pow(10.0, places); number = (int) ( number * factor ); number = number / factor; return number; }Falls was im Code sehr hässlich ist, gebt mir bescheid

Ansonsten nochmals vielen Dank für eure Hilfe.
-
icarus2 schrieb:
Falls was im Code sehr hässlich ist, gebt mir bescheid

Ok.
.cpp-Dateien inkludieren ist sehr sehr hässlich. Das macht man nicht. Die Idee von getrennter Übersetzung ist die, dass man cpp-Dateien (.cpp + #includes = Übersetzungseinheit) einzeln kompiliert und hinterher zusammenschnürt. Wenn die eine ÜE etwas von der anderen ÜE benötigt, löst man das über Header-Dateien, in denen "gemeinsame" Dinge (üblicherweise Funktionsdeklarationen und Klassendefinitionen) stehen.
Du solltest Dir auch abgewöhnen, Bezeichner zu wählen, die mit einem Unterstrich anfangen oder zwei aufeinanderfolgende Unterstriche enthalten -- auch wenn es Makros sind. Diese Bezeichner sind reserviert.
In Deinem Fall kannst Du das Zufallszeug soweit abstrahieren, dass nur noch eine freie Funktion übrig bleibt. Ob Du intern mit einem Singleton arbeitest oder nicht, interessiert den Nutzer Deiner rnd-Funktion nicht:
myrandon.hpp
#ifndef MYRANDOM_HPP_INCLUDED #define MYRANDOM_HPP_INCLUDED int myrnd(int low, int high); #endif // MYRANDOM_HPP_INCLUDEDmyrandon.cpp
#include <cstdlib> #include <ctime> #include "myrandom.hpp" namespace { int myrand_seed() { std::srand(static_cast<int>(std::time(NULL))); return 0; } } // anonymous namespace ends here int myrnd(int low, int high) { static int dummy = myrand_seed(); return low + std::rand() % (high - low + 1); }(ungetestet)
Gruß,
SP
-
Hehe, die Klasse war so im Forum gepostet ^^
Aber ich gib dir trotzdem recht. Auch im Primer stand, dass man die files auftrennen sollte. Ist .hpp einfach das neuere, für C++ gedachte, und .h das alte für C?
Danke für den Tipp mit den Bezeichnern.
In deinem Fall ist myrandon.cpp keine Klasse mehr? Ist das üblich, dass man für kleine Dinge gar keine Klasse erstellt?
Das Problem ist, dass ich aus dem Java Bereich kommme und da gibts nix anderes als Klassen. Deswegen bin ich mir nicht sicher wann man mit Klassen arbeitet und wann nicht.
-
icarus2 schrieb:
Hehe, die Klasse war so im Forum gepostet ^^
Aber ich gib dir trotzdem recht. Auch im Primer stand, dass man die files auftrennen sollte. Ist .hpp einfach das neuere, für C++ gedachte, und .h das alte für C?
Jain.
- .hpp ist durchaus mit C++ gekommen, aber viele (ich auch) benutzen dennoch für Header in C++ die Endung .h.Danke für den Tipp mit den Bezeichnern.
In deinem Fall ist myrandon.cpp keine Klasse mehr? Ist das üblich, dass man für kleine Dinge gar keine Klasse erstellt?
Das Problem ist, dass ich aus dem Java Bereich kommme und da gibts nix anderes als Klassen. Deswegen bin ich mir nicht sicher wann man mit Klassen arbeitet und wann nicht.Kommt drauf an. Es macht keinen Sinn eine Klasse lediglich zu erstellen, damit man dann statische Funktionen da drin implementiert. (das wäre ja der Java weg). Sondern man nimmt ganz natürlich normale Funktionen, wie das Sebastian zeigt. Und das ist durchaus üblich.
Ich denke man könnte sagen, dass du dort normale Funktionen machen kannst, wo du in Java eine statische Funktion einer Klasse hast, die keine Datenmember hat.
-
Also, dann kann ich frei wählen zwischen .hpp und .h, gut zu wissen

Alles klar. Ja stimmt, in Java würde man einfach in der Klasse statische Methoden implementieren.
Vielen Dank für eure Antworten.
-
Was man vielleicht auch beachten sollte, wenn man von Java nach C++ wechselt: Man sollte vorsichtiger mit objektorientierten Techniken wie Vererbung oder Polymorphie umgehen. In Java wird tendenziell eher vererbt, wo man es in C++ nicht machen würde. Alternativen, um die Funktionalität einer Klasse zu erweitern, sind oft freie Funktionen oder – falls es sich nicht um eine IS-A-Beziehung handelt – Aggregation. Dazu kommt, dass man mit Templates eine weitere Möglichkeit zur Abstraktion hat (ein ähnliches Konzept wie Generics, allerdings mächtiger). In C++ ist ausserdem nicht jede Methode automatisch virtuell, um polymorphes Verhalten muss man sich also explizit kümmern.
-
Hmm ja, bei C++ ist das ganze ja etwas komplexer, auch weil es da echte Mehrfachvererbung gibt (gibt es in Java ja nicht, da gibts dafür die Interfaces).
Ich bin gerade die Kapitel über Klassen, Objekte und Vererbung in C++ am lesen. Hoffe, dass mir das Aufschluss gibt.
Thx