2016-05-17 7 views
2

--University homework--Referenzen von Objekten in generischen Funktionen (mit Zeiger oder Nicht-Zeiger-Attribute) Rückkehr

ich bereits mit generischen Funktionen gearbeitet haben, die wie folgt aussehen:

template<class T1, class T2, int max> 
class Collection{ 
    T1* _elements1[max]; 
    T2* _elements2[max]; 
    int _count; 
public: 
    // ctor 

    bool AddElement(const T1& e1, const T2& e2) 
    { 
     for (int i = 0; i < _count; i++) 
      if (_elements1[i] == e1 && _elements2[i] == e2) 
       return false; 

     _elements1[_count] = e1; 
     _elements2[_count] = e2; 

     _count++; 

     return true; 
    } 

    int GetMax()const { return max;} 
    T1& GetElement1(int index)const { return *_elements1[index]; } 
    T2& GetElement2(int index)const { return *_elements2[index]; } 
} 

In main():

Collection<int, double, 6> collection; 

for (int i = 0; i < 6; i++) 
    collection.AddElement(i, i + 0.4); 

cout << collection << endl; 

I const auch für diese Klasse in operator<< verwenden und alles funktioniert gut, keine Beschwerden Compilerim Zusammenhang.

Aber heute habe ich eine etwas andere Version dieser Klasse ausprobiert, die wir üben sollten, weil sie in irgendeiner Form auf der Prüfung sein wird.

template<class T1, class T2, int max> 
class Collection{ 
    T1 _elements1[max]; 
    T2 _elements2[max]; 
    int _count; 
public: 
    // ctor 

    int GetMax()const { return max;} 
    T1& GetElement1(int index)const { return _elements1[index]; } 
    T2& GetElement2(int index)const { return _elements2[index]; } 
} 

Der hier Unterschied ist, dass T1 und T2 ist nicht Arrays von pointers aber Arrays von einfachen Objekten, und auch im Boden, wenn return ing, besteht keine Notwendigkeit zu dereferenzieren ist.

jedoch im letzteren Beispiel, erhalte ich diese Fehlermeldung:

error C2440: 'return' : cannot convert from 'const int' to 'int &' 

Obwohl ich es getan habe Google und fand heraus, wenn ich eine andere const vor diesen Funktionen so:

const T1& GetElement1(int index)const { return _elements1[index]; } 
const T2& GetElement2(int index)const { return _elements2[index]; } 

der Fehler ist weg.

Zugegeben, das hat mein Problem gelöst, aber ich würde lieber lernen, warum passiert das und was genau passiert unter der Haube. Wenn es eine einfache Möglichkeit gibt, den Unterschied zwischen den beiden Beispielen, die ich zur Verfügung gestellt habe, zu erklären, wäre dies sehr zu begrüßen.

+0

Was sind 'T1' und' T2' in dem Beispiel, das nicht kompiliert werden kann? – NathanOliver

+0

An dieser Stelle teste ich mit 'int' und' double' jeweils mit einer einfachen for-Schleife die Sammelfunktion AddElement (const T1 & e1, const T2 & e2). Bitte beachten Sie, dass der gleiche Test in dem anderen Beispiel angewendet wird (wobei T1 und T2 ein Array von Zeigern sind) und es nicht fehlschlägt. – developer10

+0

Also rufen Sie sowohl 'GetElement1' und' GetElement2' auf, sondern erhalten nur einen Fehler mit 'GetElement1'? – NathanOliver

Antwort

1

In erster Collection Version _elements1[index] ist vom Typ int *const&. Diese const ist, weil Sie auf _elements1 in const Methode zugreifen (eigentlich this ist const in diesem Fall), bedeutet es auch, dass Sie nicht ändern dürfen _elements1[index]. Wenn Sie _elements1[index] dereferenzieren erhalten Sie int&, das ist die Sache _elements1[index] Punkte. Sie können es also von GetElement1 zurückgeben, das T1& zurückgibt.

Nun zu Ihrer zweiten Collection-Klasse. Hier _elements1[index] innerhalb von GetElement1 Methode ist vom Typ const int&, wie zuvor const wird hinzugefügt, weil Sie auf _elements1 innerhalb der Methode const zugreifen. Nun liegt der Grund für Ihren Fehler darin, dass Sie const int& nicht implizit in int& konvertieren können.

Wenn Sie wollen lernen, welche Art hat _elements1[index] in verschiedenen Orten, die Sie unten Trick verwenden:

template<typename T> 
struct TD; 

// ... 

T1& GetElement1(int index)const { 
    TD<decltype(_elements1[index])> tt;   
    return _elements1[index]; 
    } 

Willen Ausgangsfehler mit genauen Typ des oben decltype Innere ist:

error: implicit instantiation of undefined template 'TD<const int &>' 
                 ^^^^^^^^^^^ - type of _elements1[index] 
1
T1& GetElement1(int index)const { return _elements1[index]; } 

Für die Elementfunktion wird der Compiler die Klasse selbst (this) an die Funktion als ersten Parameter übergeben. Aufgrund des const Qualifier nach Funktionsdeklaration Mitglied, ist der erste Parameter von GetElement1 konst Sammlung statt Sammlung

Edit:

#include "iostream" 
#include "string" 

template<class T1, class T2, int max> 
class Collection{ 
    T1* _elements1[max]; 
    T2* _elements2[max]; 
    int _count; 
public: 
    Collection() { 
     for (size_t i = 0; i < max; ++i) { 
      _elements1[i] = new T1{}; 
      _elements2[i] = new T2{}; 
     } 
    } 
    int GetMax()const { return max;} 
    const T1& GetElement1(int index) const { 
     // _elements1[0] = new T1{}; Error, the pointer is constant 
     _elements1[0]->resize(5); // Ok, the pointed object isn't constant 
     return *_elements1[index]; 
    } 
    const T2& GetElement2(int index) const { return *_elements2[index]; } 
}; 

int main() { 
    Collection<std::string, std::string, 5> c; 
    const std::string& rs = c.GetElement1(1); 
    return 0; 
} 
+0

OK, und warum derselbe Fehler nicht angezeigt wird, wenn T1 ein Array von Zeigern ist und ich es zurückgebe (dereferenziert)? – developer10

+1

@ developer10 - Die Zeiger zeigen auf Dinge außerhalb der Klasse. Die Zeiger könnten konstant sein, aber nicht die Dinge, auf die sie zeigen. –

+0

@BoPersson Also obwohl ich den Wert selbst zurückgebe (Beispiel mit Zeigern, notiere das "*"): 'T1 & GetElement1 (int index) const {return * _elements1 [index]; } ', macht es einen Unterschied in diesem Szenario? – developer10

Verwandte Themen