Ошибка: передача xxx в качестве аргумента 'this' аргумента xxx отбрасывает квалификаторы
#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;
}
В строке:
cout << itr->getId() << " " << itr->getName() << endl;
Выдается сообщение об ошибке:
../main.cpp: 35: ошибка: передача 'const StudentT' в качестве аргумента 'this' аргумента 'int StudentT:: getId()' отбрасывает квалификаторы
../main.cpp: 35: ошибка: передача 'const StudentT' в качестве 'this' аргумента 'std::string StudentT:: getName()' отбрасывает квалификаторы
Что не так с этим кодом? Спасибо!
Ответы
Ответ 1
Объекты в std::set
сохраняются как const StudentT
. Поэтому, когда вы пытаетесь вызвать getId()
с объектом const
, компилятор обнаруживает проблему, а именно вы вызываете неконстантную функцию-член в объекте const, которая не разрешена, потому что не-константные функции-члены не делают НИКАКИХ ОБЯЗАННОСТЕЙ, чтобы не изменить объект; поэтому компилятор должен сделать безопасное предположение, что getId()
может попытаться изменить объект, но в то же время он также замечает, что объект const; поэтому любая попытка изменить объект const должна быть ошибкой. Следовательно, компилятор генерирует сообщение об ошибке.
Решение прост: создайте функции const как:
int getId() const {
return id;
}
string getName() const {
return name;
}
Это необходимо, потому что теперь вы можете вызывать getId()
и getName()
для объектов const как:
void f(const StudentT & s)
{
cout << s.getId(); //now okay, but error with your versions
cout << s.getName(); //now okay, but error with your versions
}
В качестве побочного элемента вы должны реализовать operator<
как:
inline bool operator< (const StudentT & s1, const StudentT & s2)
{
return s1.getId() < s2.getId();
}
Параметры примечаний теперь const
.
Ответ 2
Функции-члены, которые не изменяют экземпляр класса, должны быть объявлены как const
:
int getId() const {
return id;
}
string getName() const {
return name;
}
В любое время вы видите "отбрасывает квалификаторы", это говорит о const
или volatile
.
Ответ 3
На самом деле стандарт С++ (т.е. С++ 0x draft) говорит (tnx to @Xeo и @Ben Voigt для указания на это мне):
23.2.4 Ассоциативные контейнеры
5 Для набора и мультимножества тип значения совпадает с типом ключа. Для карты и multimap он равен паре. Ключи в ассоциативной контейнер неизменен.
6 итератор ассоциативный контейнер двунаправленная категория итераторов. Для ассоциативные контейнеры, где значение тип совпадает с типом ключа, оба итератор и const_iterator постоянные итераторы. Он неуточнен будь то итератор или нет const_iterator - это один и тот же тип.
Итак, реализация Dinkumware VС++ 2008 ошибочна.
Старый ответ:
У вас есть эта ошибка, потому что в некоторых реализациях std lib set::iterator
совпадает с set::const_iterator
.
Например, libstdС++ (поставляется с g++) имеет его (см. здесь для всего исходного кода):
typedef typename _Rep_type::const_iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
В SGI docs говорится:
iterator Container Iterator used to iterate through a set.
const_iterator Container Const iterator used to iterate through a set. (Iterator and const_iterator are the same type.)
С другой стороны, VС++ 2008 Express компилирует ваш код, не жалуясь, что вы вызываете методы non const на set::iterator
s.