错误:将xxx作为xxx的'this'参数传递丢弃限定符

JAS*_*SON 412 c++

#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;
}
Run Code Online (Sandbox Code Playgroud)

排队:

cout << itr->getId() << " " << itr->getName() << endl;
Run Code Online (Sandbox Code Playgroud)

它给出了一个错误:

../main.cpp:35:错误:将'const StudentT'作为'int StudentT :: getId()'的'this'参数传递,丢弃限定符

../main.cpp:35:错误:将'const StudentT'作为'std :: string的'this'参数传递StudentT :: getName()'丢弃限定符

这段代码出了什么问题?谢谢!

Naw*_*waz 472

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

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

int getId() const {
    return id;
}
string getName() const {
    return name;
}
Run Code Online (Sandbox Code Playgroud)

这是必要的,因为现在你可以打电话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
}
Run Code Online (Sandbox Code Playgroud)

作为旁注,您应该实现operator<为:

inline bool operator< (const StudentT & s1, const StudentT & s2)
{
    return  s1.getId() < s2.getId();
}
Run Code Online (Sandbox Code Playgroud)

注意参数现在是const参考.

  • 这样清楚的解释.谢谢.但我想知道你的最后一段代码片段.为什么在函数参数中使用引用?`const StudentT&s1,const StudentT&s2`? (2认同)
  • @RafaelAdel:您使用引用来避免不必要的复制,并且使用 `const` 因为该函数不需要修改对象,所以 `const` 在编译时强制执行此操作。 (2认同)

Fre*_*son 83

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

int getId() const {
    return id;
}
string getName() const {
    return name;
}
Run Code Online (Sandbox Code Playgroud)

任何时候你看到"丢弃限定符",它正在谈论constvolatile.

  • @Mahesh:就像我说的那样 - 如果`set`中的元素被更改,顺序可能会被扰乱,然后该集合无效.在`map`中,只有键是`const`.在`set`中,整个对象确实是关键. (3认同)
  • @Fred - 您认为将const修饰符添加到不修改类实例的成员函数中是一个必要吗?在这种情况下是否还有其他原因导致错误?我对此表示怀疑,因为在我编写的大多数getter中,我都没有添加const修饰符. (2认同)

Eug*_*nca 5

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

23.2.4关联容器
5对于set和multiset,值类型与键类型相同.对于map和multimap,它等于pair.关联容器中的键是不可变的.
6关联容器的迭代器是双向迭代器类别.对于值类型与键类型相同的关联容器,iterator和const_iterator都是常量迭代器.未指定迭代器和const_iterator是否是同一类型.

因此VC++ 2008 Dinkumware实现有问题.


老答案:

你得到了这个错误,因为在std lib的某些实现中它set::iterator是相同的set::const_iterator.

例如libstdc ++(随g ++一起提供)有它(在这里查看整个源代码):

typedef typename _Rep_type::const_iterator            iterator;
typedef typename _Rep_type::const_iterator            const_iterator;
Run Code Online (Sandbox Code Playgroud)

在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.)
Run Code Online (Sandbox Code Playgroud)

另一方面,VC++ 2008 Express编译你的代码而不抱怨你在set::iterators 上调用非const方法.


Jay*_*llo 5

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

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;
    }
};
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

正如你上面看到的,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]
Run Code Online (Sandbox Code Playgroud)

为了解决上述问题,您可以:

  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,因此您给出了上述错误。

您还可以看到这个问题Meaning of 'const' last in a function statements of a class? 了解更多详情。