Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

TigerClaw25

unregistriert

1

13.07.2017, 14:37

STL und Iterator

Hallo Zusammen,
ich habe wieder einmal eine Frage, diesmal zum Thema STL. Bisher habe ich den Operator "::" kennengelernt, indem ich diesen entweder für die Definition der Funktionen außerhalb einer Klasse verwendet habe oder aber um statische Membervariablen einer Klasse zu definieren/initialisieren.

Jetzt bin ich beim The,a Vektoren und dem Iterator. Im Buch steht folgendes:

C-/C++-Quelltext

1
2
vector<int> vDaten(3);
vector<int>::iterator i;


Dass es sich hierbei um ein Klassentemplate handelt, sehe ich bereits. vDaten ist meine Klasseninstanz, wobei ich durch Übergabe der Zahl "3" an den Konstruktur eben ein Feld erzeuge mit insgesamt drei Instanzen.

Mittlerweile habe ich herausgefunden, dass der Iterator eine Art "typedef T* iterator" ist, also eine Art Ersatz für den gewählten Datentyp "<Datentyp>". Also ist "i" meine Variable bzw. in dem Fall meine Zeigervariable. Aber ich verstehe nicht ganz, welche Funktion der "::" Operator nun hat.

Wie bereits erwähnt, habe ich diesen bisher verwendet, um außerhalb der Klassendeklaration eben Funktionen zu definieren, z.B.:

C-/C++-Quelltext

1
2
3
4
5
6
7
class CSpieler{
foo();
};

CRaumschiff::foo(){
//irgendwas
}


Auch habe ich den Operator verwendet, um statische Variablen zu definieren. Die Initialisierung erfolgte dann in der main-Funktion mit "CRaumschiff::m_Zaehler=0;". Einerseits muss ich mich daran gewöhnen, dass bei der Definition/Initialisierung eben nicht der Klasseninstanzname verwendet wird, sondern der Name der Klasse selbst, nämlich "CRaumschiff". Andererseits verstehe ich nicht ganz, wozu der "::" Operator innerhalb der Mainfunktion für den Iterator gut sein soll.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

13.07.2017, 14:56

:: löst Namespaces auf. Der Iterator ist ein nested Datentyp von std::vector. Um ihn also zu verwenden, muss der volle Namenspfad angegeben werden. Das tust du mit "namespace::namespace::type::subtype::subsubtype", etc. Das ist genau dasselbe wie wenn du Methoden definierst. Du gibst den vollen Namens-Pfad an, zu dem eine definierte Methode gehört.
(Ich empfehle übrigens die Nicht-Verwendung von "using namespace xy;")
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

3

13.07.2017, 15:12

(Ich empfehle übrigens die Nicht-Verwendung von "using namespace xy;")

Vor allem nicht in Header Dateien. In Code Dateien führt es zumindest nicht zu unvorhersehbaren Fehlern, wobei ich es selbst dort nur mit Vorsicht genießen würde. Oder eben einfach nicht benutzen.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

TigerClaw25

unregistriert

4

13.07.2017, 15:33

vector ist ein Namensraum? Ich dachte, dass es sich dabei um eine Klasse, genauer um eine Templateklasse handelt. So interpretiere ich das. Aber eine Templateklasse ist ja kein Namensraum, daher bin ich mit der Aussage etwas verwirrt.

"CRaumschiff::m_Zaehler=0" ist schließlich auch kein Namensraum, sondern eine Klasse namens "CRaumschiff".

5

13.07.2017, 15:55

"CRaumschiff::m_Zaehler=0" ist schließlich auch kein Namensraum, sondern eine Klasse namens "CRaumschiff".

Sieht mir eher nach 'ner Membervariablen aus... :hmm:
fka tm

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

6

13.07.2017, 16:27

vector ist ein Namensraum? Ich dachte, dass es sich dabei um eine Klasse, genauer um eine Templateklasse handelt. So interpretiere ich das. Aber eine Templateklasse ist ja kein Namensraum, daher bin ich mit der Aussage etwas verwirrt.

std::vector ist eine Klasse. Der Namensraum ist std, der Name der Klasse ist vector. iterator ist ein Membertyp (nested class) der Klasse std::vector. Guck mal hier und hier. Am besten googlest du dich bei solchen Dingen einfach mal von vorne nach hinten. Was std ist weißt du schon, vector kennst du auch, der Operator vor iterator bereitet dir aber Probleme. Also guckst du einfach mal bei Google nach std::vector und guckst was iterator dort ist. iterator ist zum Beispiel als Membertype gelistet. Dieser Begriff sagt dir nichts weshalb du danach googlest. Dabei solltest du relativ schnell zum Begriff nested class kommen. Da du das auch nicht kennst googlest du was das ist und hast deine Frage selbst beantwortet.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

13.07.2017, 17:49

Aber eine Templateklasse ist ja kein Namensraum, daher bin ich mit der Aussage etwas verwirrt.
Klar, weil du nur das liest, was du lesen willst und das, was du nicht verstehst, einfach ignorierst. Aber um mal zum Kern der Sache zu kommen: Eine nested Class mit demselben Namen "A" kann in jeder beliebigen Klasse deklariert werden. Einfach nur "A" zu verwenden, wäre für den Compiler also mehrdeutig. Es ist aber eindeutig, wenn die Parent-Class als Namensraum interpretiert wird, denn dann ist ganz klar ein Unterschied zwischen ClassX::A und ClassB::A vorhanden. Dass eine Class nun kein Namespace ist, ist nach den Namen der Begriffe eindeutig. Aber dennoch gibt es natürlich eine sehr sehr offensichtliche Ähnlichkeit zwischen beiden. Sie können nämlich beide eindeutig Variablen und Funktionen enthalten, die es auch in anderen Scopes gibt, ohne dass es zu Konflikten kommt. Und um nun durch diese Scopes zu "navigieren", nutzt du "::".
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Wirago

Alter Hase

Beiträge: 1 193

Wohnort: Stockerau

Beruf: CRM Application Manager

  • Private Nachricht senden

8

13.07.2017, 18:14

Und um nun durch diese Scopes zu "navigieren", nutzt du "::".

Ich denke, das ist der springende Punkt zum Verständnis.
Eine Klasse, ein Namespace oder ein Interface beschreiben nicht nur deren Inhalt, sondern auch gleichzeitig einen Geltungsbereich (engl. scope) in dem eben dieser Inhalt aufrufbar ist. Und um Inhalte (Variablen, Methoden etc) aus einem bestimmten Geltungsbereich zu verwenden, benötigst du den ::-Operator.

TigerClaw25

unregistriert

9

13.07.2017, 18:45

"Und um Inhalte (Variablen, Methoden etc) aus einem bestimmten Geltungsbereich zu verwenden, benötigst du den ::-Operator."
-->Aber nur, wenn der Zugriff nicht uber eine Instanz erfolgt. Ansonsten nutze ich den Punkt oder Pfeil-Operator.

Ich war nicht aufmerksam genug, denn Beitrag richtig zu interpretieren. Was mich beim ::-Operator etwas verwirrt ist die Tatsache, dass ich diesen theoretisch nur mit Bezug auf die Klasse verwenden kann. Zumindest sieht alles danach aus. Wenn ich mir aber eine Instanz erzeuge, verwende ich diesen Operator nicht mehr, um auf Methoden oder attribute der klasse zuzugreifen, sondern entweder einen Pfeil oder einen Punkt.

Warum ich mir einen iterator über die Klasse und nicht über die Instanz erzeuge, würde ich mir momentan so erklären,dass es ähnlich ist wie bei einer statischen Membervariable, die meine erzeugten Instanzen zählt. Der iterator soll den Zugriff auf eine bestimmte Anzahl an Klassen-Elementen ermöglichen. Deshalb auch Vector<>::iterator und nicht:
Vector<> neueKlasse;
neueKlasse.iterator;

Das ist meine Interpretation. Immer dann, wenn ich auf memberfunktionen oder -Variablen oder typen einer Klasse direkt über den Klassennamen zugreife (z.b. Deklaration, Definition), tue ich das über ::. Und wenn ich eine Instanz habe, benutze ich den Punkt oder Pfeil-Operator.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

10

13.07.2017, 19:58

Eine Instanz erzeugt keinen Scope ("Geltungsbereich"). Scopes werden u.a. durch namespace, aber auch durch Klassen und Strukturen erzeugt. Jedoch nicht durch Instanzen!
Mit dem Punkt greifst du auf Member-Variablen oder Member-Funktionen (Methoden) einer Instanz zu. Der Pfeil nach einem Zeiger bedeutet einfach nur das gleiche wie der Punkt, aber nachdem der Zeiger dereferenziert wurde.
In anderen Sprachen wie C# oder Java wird übrigens beides (Scope-Navigation und Member-Zugriff) über denselben Operator gelöst, nämlich den Punkt. C++ ist da anders und trennt beides auch syntaktisch.

Unten habe ich dir ein Code-Beispiel hingeschludert, das einige falsche und einige "okaye" Dinge macht. Als kleinen Test kannst du dir ja mal in Ruhe(!) überlegen, welche Dinge OK sind und welche nicht, und warum. Weiter unten findest du dann die Auflösung zum Aufklappen! :) Es ist OK, wenn du nicht alles richtig hast. Aber wenn du dir ernsthaft Gedanken machst, wirst du sicher einen Lerneffekt erleben.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Class
{
public:
    int instanceMember;
    static int staticMember;

    class InnerClass
    {
    public:
        int instanceMember;
        static int staticMember;
    };
};

// Definition der statischen Member (Wert ist automatisch 0).
int Class::staticMember;
int Class::InnerClass::staticMember;

int main()
{
    Class.instanceMember = 42; // ?
    Class.staticMember = 42; // ?
    Class::instanceMember = 42; // ?
    Class::staticMember = 42; // ?
    std::cout << sizeof(Class::instanceMember) << std::endl; // ?
    std::cout << sizeof(Class::staticMember) << std::endl; // ?

    Class c1, c2;
    c1::instanceMember = 42; // ?
    c1::staticMember = 42; // ?
    c1.instanceMember = 42; // ?
    c1.staticMember = 42; // ?
    c2.staticMember = 43; // ?
    std::cout << (c1.staticMember == c2.staticMember ? "gleich" : "ungleich") << std::endl; // ?
    (static_cast<Class*>(nullptr))->staticMember = 42; // ?

    Class.InnerClass ic1; // ?
    Class::InnerClass ic2; // ?
    ic2.staticMember = 42; // ?
    std::cout << "Wie gross ist Class::InnerClass wohl? Antwort: " << sizeof(Class::InnerClass) << std::endl; // ?
    InnerClass::staticMember = 42; // ?
    Class::InnerClass::staticMember = 42; // ?
    c1::InnerClass ic3; // ?
}

Lösung bitte erst aufklappen, wenn du ernsthaft versucht hast zu antworten!


Werbeanzeige