【问题标题】:Trouble with constconst 的问题
【发布时间】:2010-12-07 15:08:15
【问题描述】:

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

#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 & Foo::operator[] 摆脱了那个错误。我知道我可以创建一个新的访问器来应用对 chars_ 的更改,但我想我会更新这个并找出我想要做的事情是否可行。

【问题讨论】:

    标签: c++ constants


    【解决方案1】:

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

    例如

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

    【讨论】:

      【解决方案2】:

      第一个问题是语法:

      int const operator[](int i);
      

      应该是:

      int operator[](int i) const;
      

      但是,修复失败,因为 std::map 没有 const operator[]。为什么有人会问?因为它有副作用:

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

      取自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);    
      }
      

      【讨论】:

      • int operator[](int i) const;行不通。我找到了一个可行的解决方案。 'map Foo::Chars() const;'我可以索引那个返回
      • 我确实解释了为什么仅仅改变那一行是行不通的。我为您添加了一个完整的代码示例。如果您真的有兴趣了解出了什么问题,我强烈建议您阅读我指向您的链接。
      • 我知道我需要返回一个常量。无论如何,我今天得到了我的 const 份额。奖励:我学会了做什么和做什么。告别指针。
      • 顺便说一句,我确实读过很多书。我只是通过做学得更好。单独阅读对我没有用,但它会种下一些种子,当我把手弄脏时就会发芽。
      【解决方案3】:

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

      顺便说一句,你为什么返回一个指针而不是来自operator[] 的引用?从我所见,返回引用更为习惯。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 伙计,上周我遇到了与赋值运算符有关的错误。今天我只是假设我需要一个用于我添加的新课程。我从来没有试过没有。好的,把我今天学到的三件事做起来。见鬼,如果我能每天每天学习 3 倍,我会做得很好。什么场景需要赋值运算符?
        • 只有在默认值不合适时才需要定义赋值运算符 - 例如,如果您有在构造函数中分配的指针数据成员。记住三法则:ddj.com/cpp/184401400 - 如果你有(复制构造函数、赋值运算符、析构函数)之一,那么你很有可能需要全部三个。
        【解决方案5】:

        你需要

        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 在参数列表之后,而不是返回类型。

        【讨论】:

        • @Dave:注意返回类型也可以是const。对于内置没有多大意义,因为内置类型的右值无论如何都不能修改,但这并不是真正的“错误”。
        • @Scott:“它不起作用”是什么意思?这是重载operator[] 的惯用和规范形式,所以如果这不起作用,您最好找出原因并修复它。
        • Sbi:这是“错误的”,因为它不是我们想要的意思;它意味着不同的东西。如果我们想要其他含义,那不会错,但我们不想要。
        • @Dave:这是另一个取消资格错误。我发现在 const 保护伞下避免一起访问 operator[] 解决了我的问题——通过使用访问器来检索 chars_。
        猜你喜欢
        • 2018-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多