Error: 将 xxx 作为 xxx 丢弃限定符的‘ this’参数传递

#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: error: 传递‘ const StudentT’作为‘ int StudentT: : getId ()’的‘ this’参数放弃限定符

. ./main.cpp: 35: error: 传递‘ const StudentT’作为‘ std: : string StudentT: : getName ()’的‘ this’参数,放弃限定符

这个代码有什么问题吗? 谢谢!

526418 次浏览

不修改类实例的成员函数应该声明为const:

int getId() const {
return id;
}
string getName() const {
return name;
}

任何时候你看到“discards qualifiers”,它都是在谈论constvolatile

std::set中的对象存储为const StudentT。因此,当你试图用const对象调用getId()时,编译器会检测到一个问题,主要是你在const对象上调用了一个非const成员函数,这是不允许的,因为非const成员函数会做出NO PROMISE不修改对象;所以编译器会做一个安全假设,getId()可能会尝试修改对象,但同时,它也注意到对象是const;因此任何修改const对象的尝试都应该是错误的。因此编译器生成一个错误消息。

解决方案很简单:将函数设为const as:

int getId() const {
return id;
}
string getName() const {
return name;
}

这是必要的,因为现在你可以在const对象上调用getId()getName():

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引用。

实际上,c++标准(即c++ 0x草案)说(tnx to @Xeo &@Ben Voigt指出了这一点):

23.2.4关联容器
5用于set和multiset值类型 与密钥类型相同。的地图 multimap它等于pair。键在一个关联 容器是不可变的 的迭代器 关联容器属于 双向迭代器类别。为 值所在的关联容器 类型与键类型相同 Iterator和const_iterator为 不断的迭代器。没有具体说明 是否迭代器和 Const_iterator是相同类型的

所以vc++ 2008 Dinkumware实现是错误的。


旧的回答:

你会得到这个错误,因为在std库的某些实现中,set::iteratorset::const_iterator相同。

例如,libstdc++(随g++一起提供)就有它(参见在这里获得整个源代码):

typedef typename _Rep_type::const_iterator            iterator;
typedef typename _Rep_type::const_iterator            const_iterator;

在SGI的文档中,它声明:

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.)

另一方面,vc++ 2008 Express编译你的代码时不会抱怨你在set::iterators上调用了非const方法。

让我举一个更详细的例子。对于下面的结构:

struct Count{
uint32_t c;


Count(uint32_t i=0):c(i){}


uint32_t getCount(){
return c;
}


uint32_t add(const Count& count){
uint32_t total = c + count.getCount();
return total;
}
};

enter image description here

如上所述,IDE(CLion)将给出Non-const function 'getCount' is called on the const object的提示。在方法add中,count被声明为const对象,但方法getCount不是const方法,因此count.getCount()可能会改变count中的成员。

编译错误如下(核心消息在我的编译器):

error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]

要解决上述问题,您可以:

  1. 将方法uint32_t getCount(){...}改为uint32_t getCount() const {...}。所以count.getCount()不会改变count中的成员。

  1. uint32_t add(const Count& count){...}改为uint32_t add(Count& count){...}。所以count并不关心其中成员的改变。

至于你的问题,std::set中的对象被存储为const StudentT,但方法getIdgetName不是const,所以你给出了上述错误。

你也可以查看这个问题'const'在一个类的函数声明的最后?了解更多细节。