#include <iostream>
#include <set>
using namespace std;
class StudentT {
public:
int id;
string name;
public:
StudentT(int _id, string _name) : id(_id), name(_name) {
}
int getId() {
return id;
}
string getName() {
return name;
}
};
inline bool operator< (StudentT s1, StudentT s2) {
return s1.getId() < s2.getId();
}
int main() {
set<StudentT> st;
StudentT s1(0, "Tom");
StudentT s2(1, "Tim");
st.insert(s1);
st.insert(s2);
set<StudentT> :: iterator itr;
for (itr = st.begin(); itr != st.end(); itr++) {
cout << itr->getId() << " " << itr->getName() << endl;
}
return 0;
}
W linii:
cout << itr->getId() << " " << itr->getName() << endl;
Daje błąd, który:
../main.cpp:35: error: przekazanie „const StudentT” jako argumentu „this” argumentu „int StudentT :: getId ()” odrzuca kwalifikatory
../main.cpp:35: błąd: przekazanie „const StudentT” jako argumentu „ten” argumentu „std :: string StudentT :: getName ()” powoduje odrzucenie kwalifikatorów
Co jest nie tak z tym kodem? Dziękuję Ci!
volatile
Odpowiedzi:
Obiekty w
std::set
są przechowywane jakoconst StudentT
. Kiedy więc spróbować zadzwonićgetId()
zconst
obiektu kompilator wykryje problem, głównie dzwonisz const const funkcji członka na obiekt, który nie jest dozwolony, ponieważ non-const funkcje składowe sprawiają NO obiecują nie modyfikować obiekt; więc kompilator przyjmie bezpieczne założenie, żegetId()
może próbować zmodyfikować obiekt, ale jednocześnie zauważy, że obiekt jest const; więc każda próba modyfikacji stałego obiektu powinna być błędem. Dlatego kompilator generuje komunikat o błędzie.Rozwiązanie jest proste: ustaw funkcje jako:
Jest to konieczne, ponieważ teraz możesz wywoływać
getId()
igetName()
na stałych obiektach jako:Jako sidenote powinieneś wdrożyć
operator<
jako:Uwaga parametry są teraz
const
odniesieniem.źródło
const StudentT & s1, const StudentT & s2
?const
ponieważ funkcja nie musi modyfikować obiektu, więcconst
wymusza to w czasie kompilacji.Funkcje składowe, które nie modyfikują instancji klasy, należy zadeklarować jako
const
:Ilekroć zobaczysz „odrzuca kwalifikatory”, mówi o
const
lubvolatile
.źródło
const
pochodzi, ale podejrzewam, żeset
zwraca stałe odwołanie z iteratora, aby zapobiec zmianie instancji, a tym samym unieważnieniu zestawu.foo obj;
naconst foo obj;
raz i zobacz, co się stanie. Lub przekażconst
odniesienie dofoo
.set
zostaną zmienione, kolejność może zostać zmieniona, a wtedy zestaw nie jest już ważny. W przypadkumap
tylko klucz jestconst
. Wset
przypadku cały obiekt jest naprawdę kluczem.f()
w mojej odpowiedzi.W rzeczywistości standard C ++ (tzn. Wersja robocza C ++ 0x ) mówi (tnx do @Xeo i @Ben Voigt za wskazanie mi tego):
W związku z tym implementacja Dinkumware VC ++ 2008 jest wadliwa.
Stara odpowiedź:
Wystąpił ten błąd, ponieważ w niektórych implementacjach standardowej biblioteki lib
set::iterator
jest taki sam jakset::const_iterator
.Na przykład libstdc ++ (dostarczany z g ++) ma go (zobacz tutaj cały kod źródłowy):
A w dokumentach SGI stwierdza:
Z drugiej strony VC ++ 2008 Express kompiluje kod bez narzekania, że wywołujesz metody non const na
set::iterator
s.źródło
Podam bardziej szczegółowy przykład. Co do poniższej struktury:
Jak widać powyżej, IDE (CLion) da wskazówki
Non-const function 'getCount' is called on the const object
. W metodzieadd
count
jest zadeklarowany jako obiekt const, ale metodagetCount
nie jest metodą const, więccount.getCount()
może zmienić członkówcount
.Błąd kompilacji jak poniżej (główny komunikat w moim kompilatorze):
Aby rozwiązać powyższy problem, możesz:
uint32_t getCount(){...}
nauint32_t getCount() const {...}
. Więccount.getCount()
nie zmieni członkówcount
.lub
uint32_t add(const Count& count){...}
nauint32_t add(Count& count){...}
. Więccount
nie przejmuj się zmianą członków.Jeśli chodzi o twój problem, obiekty w std :: set są przechowywane jako const StudentT, ale metoda
getId
igetName
nie są const, więc podajesz powyższy błąd.Możesz także zobaczyć to pytanie Znaczenie „const” na końcu w deklaracji funkcji klasy? po więcej szczegółów.
źródło