2010-05-16 7 views
13

Ich schreibe eine eigene Container-Klasse und habe in ein Problem gerannt, das ich nicht verstehen kann. Hier ist das Beispiel mit dem bloßen Knochen, das das Problem zeigt.C++ - Iterator und const_iterator Problem für eigene Container-Klasse

Es besteht aus einer Containerklasse und zwei Testklassen: eine Testklasse mit einem std: vector, die gut kompiliert und die zweite Testklasse, die versucht, meine eigene Containerklasse auf genau die gleiche Weise zu verwenden, aber kläglich kompiliert.

#include <vector> 
#include <algorithm> 
#include <iterator> 

using namespace std; 

template <typename T> 
class MyContainer 
{ 
public: 

    class iterator 
    { 
    public: 
    typedef iterator self_type; 
    inline iterator() { } 
    }; 

    class const_iterator 
    { 
    public: 
    typedef const_iterator self_type; 
    inline const_iterator() { } 
    }; 

    iterator begin() { 
    return iterator(); 
    } 

    const_iterator begin() const { 
    return const_iterator(); 
    } 
}; 

// This one compiles ok, using std::vector 
class TestClassVector 
{ 
public: 
    void test() { 
    vector<int>::const_iterator I=myc.begin(); 
    } 

private: 
    vector<int> myc; 
}; 

// this one fails to compile. Why? 
class TestClassMyContainer 
{ 
public: 
    void test(){ 
    MyContainer<int>::const_iterator I=myc.begin(); 
    } 

private: 
    MyContainer<int> myc; 
}; 


int main(int argc, char ** argv) 
{ 
    return 0; 
} 

gcc sagt mir:

test2.C: In member function ‘void TestClassMyContainer::test()’:

test2.C:51: error: conversion from ‘MyContainer::iterator’ to non-scalar type ‘MyContainer::const_iterator’ requested

Ich bin nicht sicher, wo und warum der Compiler will einen Iterator auf eine const_iterator für meine eigene Klasse konvertieren, aber nicht für die STL-Vektor-Klasse. Was mache ich falsch?

Antwort

9

Wenn Sie begin() aufrufen, erstellt der Compiler standardmäßig einen Aufruf an die nicht-const begin(). Da myc nicht const ist, hat es keine Möglichkeit zu wissen, dass Sie meinen, die const begin() statt der nicht-const begin() zu verwenden.

Der STL-Iterator enthält einen Umwandlungsoperator, mit dem ein iterator automatisch in einen const_iterator konvertiert werden kann. Wenn Sie diese Sie wie so ein auch hinzufügen müssen arbeiten möchten:

class iterator 
{ 
public: 
    typedef iterator self_type; 
    inline iterator() { } 

    operator const_iterator() { return const_iterator(); } 
}; 

oder erlauben const_iterator von einem iterator wie so konstruiert werden:

class const_iterator 
{ 
public: 
    typedef const_iterator self_type; 

    const_iterator(iterator&) {} 
    inline const_iterator() { } 
}; 
+0

Vielen Dank. Jetzt muss ich nur sehen, ob ich const_iterator als Freund von Iterator deklariere ... oder Accessorfunktionen in private Iterator-Member schreiben, aber das sollte machbar sein. – BaCh

3

In den Containern iterator muss der Typ in const_iterator konvertierbar sein. Es wird für die Fälle benötigt, in denen Sie einen veränderbaren Container mit einem nicht änderbaren (konstanten) Iterator durchlaufen, da dies vollkommen sinnvoll ist. In Ihrem Fall ist myc veränderbar (nicht-const), aber Sie erstellen einen konstanten Iterator.

+1

Es ist anders herum - "Iterator" muss in Const_iterator umwandelbar sein – sbk

+0

Richtig, ich habe es durcheinander gebracht. – doublep

2

Sie sollten einen Blick auf die Boost haben .Iterators-Bibliothek, besonders die iterator_facade und iterator_adaptor Abschnitte. Sie enthalten einen Aufbau eines Iterators "von Grund auf".

Es wird Ihnen zeigen, wie Iteratoren ohne zu viel Duplizierung zu schreiben, da der Code die Konstanten und Nicht-Konstanten meist abgesehen von der const Qualifikation in etwa gleich ist. Mit Vorlagen ist es möglich, sie einmal zu schreiben und dann zwei verschiedene Typen zu deklarieren, und das ist es, was die Bibliotheksdokumentation veranschaulicht.

Verwandte Themen