2009-10-17 63 views
0

我現在應該知道這一點,但我還沒有得到它。麻煩的是,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 &富:: operator []的擺脫那個錯誤的。我知道我可以創建一個新的訪問器來將更改應用於chars_,但我想我會更新這個,並且發現我想要做什麼是可能的。

回答

3

第一個問題是的語法:

int const operator[](int i); 

應該是:

int operator[](int i) const; 

然而,定影失敗,因爲性病::地圖沒有常操作符[]。爲什麼這個人可能會問?因爲它有一個副作用:

Returns a reference to the object that is associated with a particular key. If the map does not already contain such an object, operator[] inserts the default object data_type(). ... Since operator[] might insert a new element into the map, it can't possibly be a const member function. Note that the definition of operator[] is extremely simple: m[k] is equivalent to (*((m.insert(value_type(k, data_type()))).first)).second. Strictly speaking, this member function is unnecessary: it exists only for convenience.

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

順便說一下,對於這種實驗和研究,我發現在類聲明中內聯編寫所有類函數很方便。簡單地說,因爲修改類定義的速度更快,儘管一些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);  
} 
+0

int operator [](int i)const;將無法工作。我發現了一個可行的解決方案。 'map Foo :: Chars()const;'我可以索引返回 – Scott 2009-10-17 18:55:37

+0

我沒有解釋爲什麼只改變那一行就行不通。我爲你添加了一個完整的代碼示例。如果您真的有興趣瞭解發生了什麼問題,我強烈建議您閱讀我指出的鏈接。 – cdiggins 2009-10-17 19:05:42

+0

我知道我需要返回一個const。無論如何,今天我有我的份額。獎金:我學到了什麼。告別指針。 – Scott 2009-10-17 19:12:24

3

你需要做兩個不同版本的operator[],他們中的一個非const像你現在已經和另一個const返回一個const int *而不是int *。這樣,您可以在const和非const上下文中使用該運算符。

順便說一句,你爲什麼要返回一個指針而不是operator[]的引用?從我所看到的情況來看,更習慣於返回一個參考。

+0

有道理。關於指針 - 這是想到的。 – Scott 2009-10-17 15:06:34

+3

operator =也許應該返回一個參考... – leander 2009-10-17 15:08:55

5

您的operator[]是非常規的。在您的分配操作員中,爲什麼不直接訪問rhv.chars_

E.g.

Foo& Foo::operator=(const Foo &rhv) { 
    _size = rhv._size; 
    _chars = rhv._chars; 
    return *this; 
} 
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而來的參數列表後,不與返回類型。

+0

這也行不通。我會堅持一個訪問者。 – Scott 2009-10-17 18:02:39

+0

@Dave:請注意,返回類型也可以是'const'。對於內置類型來說沒有什麼意義,因爲內置類型的rvalues不能被修改,但它並不是真的「錯誤」。 – sbi 2009-10-17 18:26:28

+0

@Scott:你是什麼意思「它不工作」?這是重載'operator []'的慣用和規範形式,所以如果這不起作用,你最好找出原因並解決。 – sbi 2009-10-17 18:27:02

1

你不需要賦值運算符的。自動生成的operator=運行每個數據成員的operator=,對於您的2個數據成員類型(intstd::map)應該沒問題。

+0

男人,上週我得到了與賦值操作符有關的錯誤。今天我只是假設我需要一個爲我添加的這個新課程。我從來沒有嘗試過。好的,製作我今天學到的3件東西。地獄,如果我能每天學習每天正常的3倍,我會變得非常激烈。什麼是需要賦值運算符的場景? – Scott 2009-10-17 19:26:55

+0

只有當缺省值不合適時才需要定義賦值運算符 - 例如,如果您有在構造函數中分配的指針數據成員。記住三條法則:http://www.ddj.com/cpp/184401400 - 如果您有(複製構造函數,賦值運算符,析構函數)之一,那麼您很有可能需要這三者。 – orip 2009-10-18 07:47:48