Ein weiterer lässtiger Anfänger :-) Fragen zu Structs, Klassen und Funktionen
-
Hallo,
im Rahmen meiner Studienarbeit beschäftige ich mich zur Zeit mit C++ und habe ein paar Fragen.
Folgende Situation liegt vor. Ich habe in meiner main.cpp mehrere Variable, diese sind zu Zeit hardgecoded aber sollen mal späte rper xml eingelesen werden. Zur zeit habe ich mich für die Variante des Structs entscheiden. Die Daten sehen wie folgt aus:
// Einheit sind Nanometer! int zehn6 = 1000000; // 1 mm int zehn3 = 1000; // 1 µm // Struct-Parameter für Ebene struct sPlane { char type[10]; double Position1[3]; double Position2[3]; double Position3[3]; }; struct sPlane myPlane = { "Plane", {0,0,2*zehn6}, {1*zehn6,0,2.3*zehn6}, {0,1*zehn6,2*zehn6} }; // Struct-Parameter für Cylinder struct sCylinder { char type[10]; double Position[3]; double Axis[3]; double Radius; double Length; }; struct sCylinder myCylinder = { "Cylinder", {1*zehn6,1*zehn6,1*zehn6}, {1,0,1}, 2.5*zehn6, 6*zehn6 }; // Struct-Parameter für Kugel struct sSphere { char type[10]; double Position[3]; double Radius; }; struct sSphere mySphere = { "Sphere", {2*zehn6,2*zehn6,0}, 5*zehn6 }; // Struct-Parameter für Needle struct sNeedle { double PositionA[3]; double PositionB[3]; double PositionC[3]; double AxisA[3]; double AxisB[3]; double AxisC[3]; double Length; double Radius; }; struct sNeedle myNeedle = { {0,2*zehn6,0}, {2*zehn6,3*zehn6,0}, {4*zehn6,0,0}, {0,0,1}, {0,0,1}, {0,0,1}, 4*zehn6, 0.5*zehn6 }; // Struct-Parameter für Gripper struct sGripper { double Position[3]; double RotationAxisU[3]; double RotationAxisV[3]; double RotationAxisAngle; }; struct sGripper myGripperData = { {0,0,0}, {1*zehn6,0,2.3*zehn6}, {1*zehn6,2*zehn6,2.3*zehn6}, 15 };
Desweiteren habe ich zwei Klassen. Eine Klasse Gripper und eine Klasse Positionierer - Dabei hat ein Objekt Gripper 3 Objekte Positionierer.
In meiner main.cpp stellt sich nun folgendes Problem. Ich möchte mehrere Funktionen aufrufen. das mache ich über:
... myGripper.function1(); ...
und möchte auf möglich einfachem Weg die Daten aus den Structs übergeben. Zur Zeit würde ich es recht aufwendig machen, in der Form:
myGripper.function1(struct Plane, struc Cylinder usw...);
Kann man denn nicht ein struct machen das alle structs enthält? bzw kann man diese Daten nicht einfacher in den Klassen oder anderen cpp-Dateien verfügbar machen? Zum Beispiel über ein include oder sogar als Attribute oder Eigenschaften der KLassen Gripper oder Positionierer? Aber wie füge ich diese Daten dann den Klassen zu, diese werden ja später mal per XML in der main.cpp eingelesen...
Danke für Eure Ideen!
-
Dabauer82 schrieb:
Kann man denn nicht ein struct machen das alle structs enthält?
Klar, kann man. Deine structs sind in dem Fall zu nutzen wie Standard-Typen, pack sie einfach in ein neues struct.
Dabauer82 schrieb:
kann man diese Daten nicht einfacher in den Klassen oder anderen cpp-Dateien verfügbar machen?
Hmm, in anderen cpp-Dateien? Header mit structs per include einbinden?
In anderen Klassen? Wie wärs mit einem Member dieser Klasse, der ein Zeiger auf dein Mega-ich-hab-alles-struct ist? Den könntest du z.B. im Konstruktor zuweisen.
Mach vielleicht mal ein kleines Beispiel, wie das alles aussehen soll, ich bin da nicht ganz sicher...
-
Eine weitere Frage wäre, ob in diesem "Master"-Struct, daß du übergibst jedes Objekt nur einmal vorkommt, manche gar nicht oder mehrmals usw.
Kommt jedes nur einmal vor, dann wäre das ein Ansatz:
(... deine anderen Objekte ...) typedef struct { double length; double radius; } t_needle; typedef struct { t_needle needle; (... deine anderen Objekte ...) } t_object; (...) Beispielaufruf: void function1(t_object object);
Kommen eventuell nicht alle Objekte vor, so wollen wir natürlich nicht leere Daten übergeben. Dann würde ich es so machen:
(... deine anderen Objekte ...) typedef struct { double length; double radius; } t_needle; typedef struct { t_needle* needles; int needles_count; (... deine anderen Objekte ...) } t_object; (...) Beispielaufruf: void function1(t_object object);
Und den Pointer zu den Structs dynamisch füllen. Also als Array mit vorher unbekannter Größe.
Die Objekte kannst du dann Traversen z.b. mit
for(int i = 0; i < object.needles_count; i++) object.needles[i]->length = 3;
Am Elegantesten wäre aber vermutlich folgendes:
- Mach alle Structs die gleiche Länge (z.B. 32 oder 64 Byte)
- Erzeuge ein enum mit den verschiedenen Geometrischen Typen
- jedes object hat einen Pointer auf dynamische struct daten
- das struct objects speichert ein array auf objects und dessen count
z.B.
typedef struct { double length; double radius; } t_needle; typedef struct { int type; // enum-wert (needle, kugel, gerade, linie, etc.) void* object; // pointer auf struct der jeweiligen kategorie } t_object; typedef struct { int count; t_object* objects; } t_objects; (...) // dann müsste in deiner Funktion nach Übergabe sowas stehen void function(t_objects objects) { for(int i = 0; i < objects.count; i++) { t_object* object = objects.objects[i]; switch(object->type { case(needle): object->radius = 3; break; } } }
Das wären meine Vorschläge. Ich hab sie jetzt nicht probiert, aber das Prinzip sollte klar sein.
-
Sieht so aus als wuerde Dir ein vernuenftiges hierarchisches Klassenlayout sehr viel Arbeit im weiteren Verlauf Deines Projektes abnehmen.
struct Vector { double x,y,z; }; struct Object { int typeID; Vector position; }; struct Sphere : Object { double Radius; }; struct Plane : Object { Vector normal; }; // ...
-
hellihjb schrieb:
Sieht so aus als wuerde Dir ein vernuenftiges hierarchisches Klassenlayout sehr viel Arbeit im weiteren Verlauf Deines Projektes abnehmen.
jep!
-
NDEBUG schrieb:
...
(... deine anderen Objekte ...) typedef struct { //...
Da er C++ erwähnt hat, würde ich garnicht erst "typedef struct" zeigen. Das sind C-Relikte (struct, class, enum, union... sind bereits von sich aus "Typdefinitionen")...
-
@all,
hui, da hat sich nun aber einiges getan. Ich muss erst mal alle eure Infos verarbeiten
Werde dann wieder Stellung dazu nehmen.
Genrell ist zu sagen, dass leere Daten vorkommen können, d.h das Objekt Gripper kann immer nur einen Körper handhaben, also entweder eine Kugel, oder eine Ebene oder einen Zylinder. In dem Fall, dass z.B ein Körper Kugel vorliegt, muss man die structs Ebene und Zylinder nicht übergeben. Die wäre dann über.
Ich selbst vermute mal, dass KLassen das Beste wären. Aber mir fehlt es da definitv an Erfahrung - die sich wenn ich ehrlich bin, auf ein Video2Brain-Tutorial und ein kleines Buch stützt. Das Problem an Klassen ist bei mir zur Zeit einfach noch, dass ich diese nicht 'lesen' kann. Schwer vorzustellen. Meine weiteren Progammierkenntnisse basieren auf Matlab - und dort ist es relativ einfach Programm zusammenzuwerfen. Aber ich bin lernwillig
Danke noch mal für Eure Antworten, ich hoffe, bei baldige Fragen wieder auf den ein oder Anderen zählen zu können
Grüße
-
So, ich habe mich nun wieder etwas mit der Sache beschäftig und versucht eure Kommentare einfließen zu lassen. Leider verstehe ich das ein oder andere nicht.
Im folgenden habe ich meine erste Programmstruktur mit der neuen Struct-Hierarchie beigefügt. Ich denke so ist es leichter einsehbar was meine Probleme sind.
Die Sache ist so: Ich habe eine main.cpp in der die oben erwähnten Structs zur Verfügung gestellet werden und welche ich dann an eine Funktion übergeben möchte. Die Funktionen befinden sich in dem Objekt myGripper (gripper.cpp). Diese beiden Dateien (*.cpp und *.h) habe ich auch beigefügt.
Bei den Structs habe ich es mir bisweilen so gedacht, dass ich für jedes Objekt ein struct mache (Plane, Cylinder, Sphere - mehr gibt es nicht) sowie für meine anderen Daten (3xNeedle, Rotationsdaten und Gripperposition) und diese in einem Hauptstruct (myGripperData) zusammenpacke und dann übergebe.
Dabei ist zu beachten, dass immer nur ein struct der Objekte übergeben wird. Bisweilen dachte ich mir das so, dass ich die structs Cylinder und Sphere NULL setzte wenn diese nicht vorliegen. Die structs Needle (3x), Gripperposition und Rotationdata sind hingegen immer gesetzt. Die Sache mit den Zeigern scheint mir logischer, aber diese verstehe ich noch nicht. Habe leider zu wenig Erfahrung.Das mit dem enum-Werte habe ich prinzipiell auch verstanden, aber ich weiß nicht wie ich es anwenden kann.
main.cpp
//////////////////////////////////////////////////////////////////////////////////////// // Includebereich //////////////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Gripper.h" #include "Positioner.h" //////////////////////////////////////////////////////////////////////////////////////// // Main-Bereich //////////////////////////////////////////////////////////////////////////////////////// int _tmain(int argc, _TCHAR* argv[]) { //////////////////////////////////////////////////////////////////////////////////////// // DATEN, WELCHE VON AUSSEN FÜR MICH ZUR VERFÜGUNG GESTELLT WERDEN UND VERMUTLICH // ÜBER XML EINGELESEN WERDEN !!! -> JONAS UND DANIEL S. KONTAKTIEREN //////////////////////////////////////////////////////////////////////////////////////// // Einheit sind Nanometer! int zehn6 = 1000000; // 1 mm int zehn3 = 1000; // 1 µm // Struct-Parameter für Ebene struct sPlane myPlane = { Plane, {0,0,2*zehn6}, {1*zehn6,0,2.3*zehn6}, {0,1*zehn6,2*zehn6} }; // Struct-Parameter für Cylinder struct sCylinder myCylinder = { Cylinder, {1*zehn6,1*zehn6,1*zehn6}, {1,0,1}, 2.5*zehn6, 6*zehn6 }; // Struct-Parameter für Kugel struct sSphere mySphere = { Sphere, {2*zehn6,2*zehn6,0}, 5*zehn6 }; // Struct-Parameter für Needle1 bis 3 struct sNeedle myNeedle1 = { {0,2*zehn6,0}, {0,0,1}, 4*zehn6, 0.5*zehn6 }; struct sNeedle myNeedle2 = { {2*zehn6,3*zehn6,0}, {0,0,1}, 4*zehn6, 0.5*zehn6 }; struct sNeedle myNeedle3 = { {4*zehn6,0,0}, {0,0,1}, 4*zehn6, 0.5*zehn6 }; // Rotationsdaten struct sRotationData myRotationData = { {1*zehn6,0,2.3*zehn6}, {1*zehn6,2*zehn6,2.3*zehn6}, 15 }; // Parameter des Greifers struct sGripperData myGripperDataPlane = { myNeedle1, myNeedle2, myNeedle3, myPlane, myCylinder, mySphere, myRotationData, {0,0,0} }; // Erzeuge 3PunktGreifer Objekt mit Namen myGripper vom Typ Gripper Gripper myGripper; ///////////////////////////////////////////// // Initialisierung des Systems ///////////////////////////////////////////// if(!myGripper.systemInitialize()) { cout << "\n\nInitialisierung fehlgeschlagen"<< endl; // Weiter mit Return cin.clear(); cin.ignore(256, '\n'); cout << "\n\n>> Weiter mit Return..." << endl; cin.get(); return 1; } // Test myGripper.moveObjectApproach(myGripperDataPlane, 60000, 500000);
meine gripper.h
#pragma once #include "Position.h" #include "Positioner.h" #include "MCSControl.h" // Definitionsbereich der Structs enum Objects { Plane, Cylinder, Sphere }; struct sNeedle { double Position[3]; double Axis[3]; double Length; double Radius; }; struct sPlane { int type; double Position1[3]; double Position2[3]; double Position3[3]; }; struct sCylinder { int type; double Position[3]; double Axis[3]; double Radius; double Length; }; struct sSphere { int type; double Position[3]; double Radius; }; struct sRotationData { double VectorU[3]; double VectorV[3]; int RotationAngle; }; struct sGripperData { struct sNeedle myNeedle1; struct sNeedle myNeedle2; struct sNeedle myNeedle3; struct sPlane myPlane; struct sCylinder myCylinder; struct sSphere mySphere; struct sRotationData myRotationData; double Gripperposition[3]; }; class Gripper { private: static const int numPositioner = 3; Positioner* myPositioner[numPositioner]; public: Gripper(void); ~Gripper(void); int systemInitialize(void); //done // Funktion fährt Objekt an void moveObjectApproach(struct sGripperData myGripperData, unsigned int holdTime, unsigned int speed); // Funktion dreht Objekt um Achse void moveObjectRotation(struct sGripperData myGripperData, unsigned int holdTime, unsigned int speed); // Funktion verfährt relativ um ein Inkrement void moveObjectRelative(struct sGripperData myGripperData, double myInkrement[3], unsigned int holdTime, unsigned int speed); // Funktion verfährt absolut auf einen Punkt void moveObjectAbsolute(struct sGripperData myGripperData, int myPosition, unsigned int holdTime, unsigned int speed); // Funktion schaltet Druckluft an und greift Objekt void gripObject(); // Funktion schaltet Druckluft ab und lässt Objekt los void releaseObject(); };
meine gripper.cpp
#include "StdAfx.h" #include "Gripper.h" Gripper::Gripper(void) { for (int i=0; i < Gripper::numPositioner; i++) { myPositioner[i]= new Positioner(i); } } Gripper::~Gripper(void) { for (int i=0; i < Gripper::numPositioner; i++) { delete myPositioner[i]; } } // Funktion fährt Objekt an void Gripper::moveObjectApproach(sGripperData myGripperData, unsigned int holdTime, unsigned int speed) { if (myGripperData.myPlane != NULL) { cout << "Plane" << endl; } else if (myGripperData.myCylinder != NULL) { cout << "Cylinder" << endl; } else if (myGripperData.mySphere != NULL) { cout << "Kugel" << endl; }; }
Mögt ihr mir nochmal erklären wie das besser zu lösen ist? das wäre super. Danke
-
Das mit den enums brauchst du nicht, da jedes struct schon weiß welches struct es ist. Das mit den enums war folgende Idee: mit den enums bist du in der Lage z.B. für den Gripper eine Funktion zu bauen, die ein Object erwartet ohne vorher genau festzulegen, welches object da übergeben wird. Das heißt du müsstest nicht eine Funktion für jedes objekt schreiben, z.b. moveplane, movecube, movecircle, move..., sondern du wärst in der Lage gewesen moveobject zu schreiben, das dann in der Lage gewesen wäre mit jedem Objekt umzugehen. Du übergibst im Moment dieses große struct und damit brauchst du die enums und die type-Variablen in den structs nicht.
das wäre die Idee gewesen hier: ob du sowas brauchst mußt du entscheiden!
// Definitionsbereich der Structs enum { PLANE, CYLINDER, SPHERE }; // ... struct object_s { int type; //<- hier kommt rein um welches objekt es sich aktuell handelt void *object; //<- das hier ist ein pointer, der auf ein struct des jew. objects zeigt }; // ... struct sNeedle { double Position[3]; double Axis[3]; double Length; double Radius; }; struct sPlane { double Position1[3]; double Position2[3]; double Position3[3]; }; struct sCylinder { double Position[3]; double Axis[3]; double Radius; double Length; }; struct sSphere { double Position[3]; double Radius; }; struct sRotationData { double VectorU[3]; double VectorV[3]; int RotationAngle; }; struct sGripperData { //struct sNeedle myNeedle1; // hier ein array von sNeedle vllt? //struct sNeedle myNeedle2; //struct sNeedle myNeedle3; struct sNeedle myNeedle[3]; //! //struct sPlane myPlane; // hier jetzt nur noch object! //struct sCylinder myCylinder; //struct sSphere mySphere; struct object myObject; //! struct sRotationData myRotationData; double Gripperposition[3]; };