Forum: Mikrocontroller und Digitale Elektronik avr studio 6.1 c++ classes


von micro u. (Gast)


Lesenswert?

hallo
ich würde gerne c++ classen programmieren um servos anzusteuern.
somit könnte ich fertige servo objekte erstellen.

nun, ich stelle mir darunter sowas vor:
1
class Servo{
2
  // class private member
3
  double iniPos;
4
public:
5
  //constructor 
6
  Servo(double iniPos):iniPos(iniPos){
7
  }
8
  //methods
9
  void goTo(double pos){
10
    // do something
11
  }
12
  void turn(double angle){
13
    // do something
14
  }
15
};

avr studio 6.1 schlägt mir aber folgende files vor, wenn ich ein 
klasen-file hinzufüge:

CServo.h
1
#ifndef __CSERVO_H__
2
#define __CSERVO_H__
3
4
5
class CServo
6
{
7
//variables
8
public:
9
protected:
10
private:
11
12
//functions
13
public:
14
  CServo();
15
  ~CServo();
16
protected:
17
private:
18
  CServo( const CServo &c );
19
  CServo& operator=( const CServo &c );
20
21
}; //CServo
22
23
#endif //__CSERVO_H__

CServo.cpp
1
#include "CServo.h"
2
3
// default constructor
4
CServo::CServo()
5
{
6
} //CServo
7
8
// default destructor
9
CServo::~CServo()
10
{
11
} //~CServo

- wie muss ich diese files nun bearbeiten, um ans ziel zu kommen?
soweit ich verstanden habe ist ja die .h nur dazu da die "verweise" zu 
machen, den gesammten code jedoch schmeiss ich dann in die .cpp.
Ich würde jetzt alle meine member die ich will in der .h anlegen und 
alle methoden in der .cpp programmieren, construktor werden nicht genau 
so gemacht wie ich das gelernt habe, also so sein lassen oder fehlt da 
noch was?

- das protected ist mir neu, was is da die funktion? public ersichtlich 
aber nur private beschreibbar? Oo

von micro u. (Gast)


Lesenswert?

ich würd das jetzt so schreiben:

.h
1
#ifndef __CSERVO_H__
2
#define __CSERVO_H__
3
4
5
class CServo
6
{
7
//variables
8
public:
9
protected:
10
private:
11
// class private member
12
double iniPos;
13
14
//functions
15
public:
16
  CServo();
17
  ~CServo();
18
protected:
19
private:
20
  CServo( const CServo &c );        // was ist das?
21
  CServo& operator=( const CServo &c );  // was ist das?
22
23
}; //CServo
24
25
#endif //__CSERVO_H__

.cpp
1
#include "CServo.h"
2
3
// default constructor
4
CServo::CServo()
5
{
6
} //CServo
7
8
// default destructor
9
CServo::~CServo()
10
{
11
} //~CServo
12
13
// methodes
14
void goTo(double pos){
15
  // do something
16
}
17
void turn(double angle){
18
  // do something
19
}

von Kaj (Gast)


Lesenswert?

micro uc schrieb:
> das protected ist mir neu, was is da die funktion? public ersichtlich
> aber nur private beschreibbar?

Stichwort: Vererbung bzw. ich nenne es mal "zugriffsrechte"

Eine funktion aus dem private-Bereich kannst du nur innerhalb der Klasse 
aufrufen, aber nicht in einer Funktion außerhalb der Klasse.

Google und ein bisschen ausprobieren ist da ganz hilfreich ;)

Grüße

von Oliver (Gast)


Lesenswert?

micro uc schrieb:
> avr studio 6.1 schlägt mir aber folgende files vor, wenn ich ein
> klasen-file hinzufüge:

Wie du ganz richtig erkannt hast, ist das nichts weiter als ein 
Vorschlag. Wenn dir das nicht gefällt, dann lösch einfach alles, was da 
steht, und schreib hin, was du für richtig hälst.

Ein C++-Buch wäre allerdings auch zu empfehlen...

Oliver

von micro u. (Gast)


Lesenswert?

hallo
ja wie erwähnt, private und public ist mir bekannt. das protected is die 
frage. aber nebensache. mich interessiert hauptsächlich der aufbau der 
classe in den beiden files!

von micro u. (Gast)


Lesenswert?

@oli
kann ich dann alles in die .h packen und das mit dem zusatzfile .cpp 
sein lassen?

von Karl H. (kbuchegg)


Lesenswert?

micro uc schrieb:
> hallo
> ja wie erwähnt, private und public ist mir bekannt. das protected is die
> frage. aber nebensache. mich interessiert hauptsächlich der aufbau der
> classe in den beiden files!

Tja.
Das Problem ist, das man dir jetzt einen Vortrag halten müsste, der sich 
in einem C++ Buch über gut und gerne mindestens 20 Seiten erstreckt.

Das man mehrere Konstruktoren haben kann, wirst du wahrscheinlich 
wissen. Einer davon ist ein Default Konstruktor, der immer dann benutzt 
wird, wenn keine weiterern Parameter an den Konstruktor zu übergeben 
sind.

Das ist der hier
1
  CServo();

Er kommt zb dann zum Einsatz, wenn einfach nur 1 Objekt erzeugt werden 
soll
1
int main()
2
{
3
  CServo meinServo;       // Default Konstruktor wird aufgerufen

Ein anderer Konstruktor ist der hier
1
  CServo( const CServo &c );        // was ist das?

das ist ein Copy-Konstruktor. An und für sich ein Konstruktor wie jeder 
andere, also auch wie deiner hier
1
  Servo(double iniPos)
nur mit dem Unterschied, dass er eine Referenz auf ein Objekt vom 
gleichen Typ nimmt. D.h. er wird dann eingesetzt, wenn es gilt, eine 
Kopie von einem Objekt zu machen
zb hier
1
int main()
2
{
3
  CServo ServoA;
4
  CServo ServoB( ServoA );

ServoB ist also eine exakte Kopie vom ServoA.
OK, in dieser Form ist das natürlich Unsinn und das wird so kein Mensch 
machen. Aber an anderen Stellen kommt es schon vor, dass man eine Kopie 
von einem Objekt braucht. Denke zb daran, was passieren muss, wenn man 
ein Objekt in einen Container einfügt. Dann gibt es 2 Möglichkeiten: 
entweder man fügt eine Referenz auf das Originalobjekt in den Container 
ein, oder man erzeugt eine Kopie vom Originalobjekt und fügt das in den 
Container ein. Die erste Variante hat den Nachteil, dass dann das 
Originalobjekt weiter bestehen muss, solange es eine Referenz davon im 
Container gibt. Bei der 2.ten Varianten hab ich dieses Problem nicht. 
Denn das Originalobjekt braucht keiner mehr, nachdem die Kopie gezogen 
wurde. D.h. das Originalobjekt kann auch zerstört werden, das betrifft 
die Kopie nicht.

Aber auch hier
1
void foo( CServo a )
2
{
3
  ...
4
}
5
6
int main()
7
{
8
  CServo b;
9
10
  foo( b );
11
}

wird eine Kopie erzeugt. innerhalb von foo ist a eine Kopie von b. Und 
erzeugt wird diese Kopier durch den Aufruf des Copy Konstruktors ehe 
dann der Funktionsaufruf der Funktion foo gemacht wird und der dann 
diese Kopie übergeben wird.

Das hier
1
  CServo& operator=( const CServo &c );  // was ist das?
ist der Zuweisungsoperator. Er hat eine ähnliche Aufgabe wird allerdings 
bei Zuweisungen eingesetzt
1
int main()
2
{
3
  CServo ServoA;
4
  CServo ServoB;
5
6
  ServoB = ServoA;
7
}

An der Stelle der Zuweisung wird zum Zwecke der Durchführung der 
Zuweisung genau diese Funktion aufgerufen. Ihre Aufgabe ist es, im 
Original von B alles zu tun, was es zu tun gibt um das bisherige B 
Objekt aufzulösen und die Werte vom A Objekt nach B zu übernehmen.


Soweit so gut.
Aber was hat es jetzt mit dem private auf sich?

Das ist ganz einfach.
Alle Member-Funktion, die private definiert sind, können nur von 
innerhalb genau dieser Klasse benutzt werden. D.h. mit obiger 
vorgeschlagener Funktion geht das gar nicht
1
void foo( CServo a )
2
{
3
  ...
4
}
5
6
int main()
7
{
8
  CServo ServoA;
9
  CServo ServoB( ServoA );
10
11
  foo( ServoA );

den weder main noch foo sind Teil der Klasse. Der Copy Konstruktor ist 
aber ausserhalb der Klasse nicht zugreifbar! Der Compiler muss dir das 
also verbieten. Mit anderen Worten: die Klasse hat sich selbst davor 
geschützt, dass irgendein anderer Code je eine Kopie eines Objektes 
machen kann. Man kann Objekte anlegen, mann kann sie auch zerstören, 
aber kopiern ... no, no ... das geht nicht.

Selbiges mit dem Zuweisungsoperator. Auch der ist private. Und damit 
sind dann auch alle derartigen Zuweisungen
1
   ServoB = ServoA;
nicht compilierbar.

Effektiv hat damit die Klasse ihrem Verwender eine Schranke auferlegt, 
was er tun darf und was nicht.

Warum man das in manchen Fällen haben will .... das ist eine andere 
Geschichte, die allerdings noch umfangreicher zu erzählen ist und worauf 
ich momentan ehrlich gesagt keine Lust habe. Denn dazu gibt es C++ 
Bücher.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

micro uc schrieb:
> @oli
> kann ich dann alles in die .h packen und das mit dem zusatzfile .cpp
> sein lassen?


Warum willst du das tun?
Was hat das damit zu tun, was dir der Wizard vorgeschlagen hat?

von micro u. (Gast)


Lesenswert?

um es einfach zu halten würd ich somit meinen vorgeschalgenen code 
verwenden und da drin alles programmieren, anstatt den vorschlag zu 
benutzen.

von Karl H. (kbuchegg)


Lesenswert?

Um es einfach zu sagen, unterscheidet sich deine Klasse bis auf 1 
kleines Detail praktisch in nichts vom Vorschlag.
Und das kleine Detail ist: der Vorschlag hat für dich mitgedacht und 
greift dir ein wenig unter die Arme, in dem er potentiell gefährliche 
Operationen (kopieren und zuweisen) erst mal unterbindet, solange du 
nicht weißt, welchen Ärger du dir damit einhandeln kannst. Und er macht 
das so, dass diese Unterbindung auch dann greift, wenn du selbst mglw. 
gar nicht merkst, dass du unabsichtlich eine Kopie ziehst. Wie zb durch 
ein vergessenes & in der Argumentliste einer Funktion.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Ob du die Implementierung der Methoden hingegen in ein eigenes cpp File 
auslagerst, oder ob du die Funktionen direkt im Header File inline 
implementierst, ist ein Detail, dass sich beim Funktions-inlining an der 
Aufrufstelle auswirkt. Mehr aber auch nicht.
Und ob der COmpiler tatsächlich inlined oder nicht - das entscheidet der 
sowieso selber. Eine inline angegebene Methode ist ein Vorschlag an den 
Compiler zum inlinen. Aber es ist für ihn keine Verpflichtung.

Üblicherweise macht man kurze Funktionen (typischerweise die Getter und 
Setter) direkt inline in der Klassendefinition im Header File und den 
ganzen Rest an umfangreicheren Funktionen im cpp File.

Wenn es das ist, was du wissen willst.

: Bearbeitet durch User
von micro u. (Gast)


Lesenswert?

okay super. vielen dank für die erklärungen!
wer ich mal so versuchen umzusetzen.

thread closed.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.