常见问题

时间:2009-10-17 14:53:14

标签: c++ const

我现在应该得到这个,但我还没有得到它。问题是operator =的参数可能是非const,但是它会破坏std :: vector :: push_back,因为它使项目为const,所以operator =必须接受一个const对象。好吧,我不确定我应该如何修改这个像这样工作的对象。

#include <vector>
#include <map>
#include <iostream>

using namespace std;

int font[] = {0, 31, 0, 31, 0, 31, 0, 31};

class Foo {
    int size_;
    std::map<int, int> chars_;
    public:
    Foo(int *font, int size);
    unsigned int Size() const { return size_; }
    void Add(int ch);
    bool operator==(const Foo &rhv) const;
    int &operator[](int i);
    int const operator[](int i);
    Foo operator=(const Foo &rhv);
};

Foo::Foo(int *font, int size) {
    for(int i = 0; i < size; i++ ) {
        chars_[size_++] = font[i];
    }
}

bool Foo::operator==(const Foo &rhv) const {
    if(Size() != rhv.Size()) return false;
    /*for(int i = 0; i < Size(); i++ ) {
        if ( chars_[i] != *rhv[i] ) 
            return false;
    }*/
    return true;
}

int &Foo::operator[](int i) {
    return chars_[i];
}

int const Foo::operator[](int i) {
    return chars_[i];
}

Foo Foo::operator=(const Foo &rhv) {
    if( this == &rhv ) return *this;
    for(unsigned int i = 0; i < rhv.Size(); i++ ) {
        //Add(*rhv[i]);
        //chars_[size_++] = rhv[i];
    }
    return *this;
}

void Foo::Add(int ch) {
    chars_[size_++] = ch;
}

int main()
{
    vector<Foo> baz;
    Foo bar = Foo(font, 8);
    baz.push_back(bar);    
}

编辑:好吧,我花了一些时间再次阅读const。我甚至想做什么?我问的原因是因为这句话: 如果在没有const限定符的情况下它没有编译,并且您正在返回一个引用或指向可能是该对象的一部分的指针,那么您的设计就会很糟糕。

我考虑到了这一点,并且没有在const方法中返回引用。这产生了这个错误:

test.cpp:18: error: 'const int Foo::operator[](int)' cannot be overloaded
test.cpp:17: error: with 'int& Foo::operator[](int)'
test.cpp:41: error: prototype for 'const int Foo::operator[](int)' does not match any in class 'Foo'
test.cpp:37: error: candidate is: int& Foo::operator[](int)

摆脱int&amp; Foo :: operator []摆脱了这个错误。我知道我可以创建一个新的访问器来将更改应用到chars_,但我想我会更新它并找出我想要做的事情是否可行。

5 个答案:

答案 0 :(得分:5)

您的operator[]非常规。在您的分配运算符中,为什么不直接访问rhv.chars_

E.g。

Foo& Foo::operator=(const Foo &rhv) {
    _size = rhv._size;
    _chars = rhv._chars;
    return *this;
}

答案 1 :(得分:3)

你需要制作两个不同版本的operator[],其中一个非const,就像你现在一样,另一个const返回const int *而不是int *。这样,您就可以在const和非const上下文中使用运算符。

顺便说一下,为什么要从operator[]返回指针而不是引用?从我所看到的情况来看,返回引用更为习惯。

答案 2 :(得分:3)

第一个问题是语法:

int const operator[](int i);

应该是:

int operator[](int i) const;

然而,修复失败,因为std :: map没有const运算符[]。为什么那个人会问?因为它有副作用:

  

返回对该对象的引用   与特定键相关联。   如果地图尚未包含   这样的对象,operator []插入   默认对象data_type()。   ...   由于operator []可能会插入一个新的   元素进入地图,它不能   可能是一个const成员函数。   注意operator []的定义   非常简单:m [k]是   相当于   (*((m.insert(VALUE_TYPE(K,   DATA_TYPE())))。第一))。第二。   严格来说,这个成员   功能是不必要的:它存在   只是为了方便。

取自http://www.sgi.com/tech/stl/Map.html。因此,您将需要使用find函数而不是operator []。

顺便说一句,对于这种实验和研究,我发现在类声明中内联编写所有类函数很方便。简单地说,因为修改类定义的速度更快,尽管一些C ++纯粹主义者将其描述为坏风格。

[编辑:这是一个完整的解决方案]

class Foo {
    size_t size_;
    std::map<int, int> chars_;
 public:
    Foo(int *font, size_t size) 
        : size_(size) 
    { 
        // size should be of type "size_t" for consistency with standard library
        // in the original example "unsigned int" and "int" was mixed throughout
        for (size_t i=0; i < size; ++i)
            // Reuse the add function.  
            Add(font[i]);
    }
    size_t Size() const { 
        return size_; 
    }
    void Add(int ch) { 
        chars_[size_++] = ch;
    }
    bool operator==(const Foo &rhv) const {
        if (&rhv == this) return true;
        if (rhv.Size() != size_) return false;
        for (size_t i=0; i < size_; ++i)
            if (rhv[i] != (*this)[i])
                return false;
        return true;
    }   
    int& operator[](size_t i) {
        assert(i < size_);
        return chars_.find(i)->second;
    }
    const int& operator[](size_t i) const {
        assert(i < size_);
        return chars_.find(i)->second;
    }
    Foo& operator=(const Foo &rhv) {
        size_ = rhv.size_;
        chars_ = rhv.chars_;
        return *this;
    }
};

int main()
{
    std::vector<Foo> baz;
    Foo bar = Foo(font, 8);
    baz.push_back(bar);    
}

答案 3 :(得分:1)

根本不需要赋值运算符。运行每个数据成员的operator=的自动生成的operator=应该适用于您的2种数据成员类型(intstd::map)。

答案 4 :(得分:0)

你需要

class Foo {
    //...
    int &operator[](int i);
    int  operator[](int i) const;
    //...
};

int &Foo::operator[](int i) {
    return chars_[i];
}

int Foo::operator[](int i) const {
    return chars_[i];
}

即。 const位于参数列表之后,而不是返回类型。

相关问题