avr studio 6.1 c++ classes

Gast #3353854
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
Gast
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
}
Gast
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
Gast
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
Gast
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!
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.
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.
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 13 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.