определяющий оператор [] для чтения и записи - PullRequest
6 голосов
/ 09 марта 2011

В книге «Язык программирования C ++» автор привел следующий пример вместе с несколькими утверждениями:

Определить оператор, такой как [], который будет использоваться как для чтения, так и для записи, сложно, когда недопустимо просто возвращать ссылку и позволить пользователю решать, что с ней делать.

Cref, чтобы помочь реализовать оператор индекса, который различает чтение и запись.

Почему [] трудно определить, когда он используется для чтения и письма? Как определение класса Cref помогает решить эту проблему?

  class String{
     struct Srep; 
     Srep *rep; 

     public: 
        class Cref;

     // some definitions here
     void check (int i) const { if (i<0 || rep->sz<=i) throw Range( );}

     char read( int i) const {return rep->s[i];}
     void write(int i, char c){ rep=rep->get_own_copy(); rep->s[i]=c;}

     Cref operator[] (int i){ check(i); return Cref(*this, i);}
     char operator[] (int i) const{check(i); return rep->s{i];}

   }

  class String::Cref{
    friend class String;
          String& s;
          int i;
          Cref(String& ss, int ii): s(ss),i(ii) {}
    public:
          operator char( ) { return s.read(i);}
          void operator=(char c){s.write(i,c);}
  };

Ответы [ 3 ]

8 голосов
/ 09 марта 2011

Если вы не определили класс Cref, который решает эту проблему, тогда вы должны сделать то, что std::map делает:

template class <K,V> class map{
   V& operator[](K const & key);
}

Возвращает ссылку, которая должна быть подкреплена допустимой ячейкой памяти, и, следовательно,

std::map<string,string> m;
m["foo"];
assert(m.find("foo") != m.end());

Утверждение выполнится успешно (то есть "foo" теперь является действительным ключом на карте), даже если вы никогда не назначали что-либо для m["foo"].

Это нелогичное поведение может быть исправлено классом Cref в вашем примере - он может выполнять соответствующую логику для создания m["foo"] только при назначении ссылки и гарантировать, что m.find("foo") == m.end(), если вы этого не сделали выполнить какое-то задание, когда вы попытались прочитать несуществующий m["foo"].

Аналогично, в вашем классе String (который является строкой с подсчетом ссылок - строки совместно используют свои строковые данные, и при изменении строки, данные которой совместно используются с другой строкой, создается новая копия), вы бы необходимо сделать копию при использовании operator[] для чтения символов. Использование класса Cref позволяет вам делать копии только при использовании operator[] для записи.

3 голосов
/ 09 марта 2011
String s;
s[0] = 5;

вызовет String::operator [](int), а затем String::Cref::operator =(char).

Однако

String s;
char c = s[0];

вызовет String::operator [](int), а затем String::Cref::operator char().

При чтении вызывается String::Cref::operator char, а при записи вызывается String::Cref::operator = - это позволяет различать чтение и запись.

1 голос
/ 09 марта 2011

Почему [] трудно определить , когда его следует использовать для различия между чтением и письмом?

Это потому, что неконстантный operator[] вызывается всякий раз, когда у вас есть неконстантный объект, даже если вы используете его только для чтения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...