定义读写操作符 [ ]
在《The C++Programming Language》一书中,作者给出了以下示例以及几条语句:
定义一个用于读取和写入的运算符(例如 [])是很困难的,因为简单地返回引用并让用户决定如何处理它是不可接受的。
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);}
};
In the book of "The C++ Programming Language", the author gave the following example along with several statements:
Defining an operator, such as [], to be used for both reading and writing is difficult where it is not acceptable simply to return a reference and let the user decide what to do with it.
Cref, is to help implement a subscript operator that distinguishes between reading and writing.
Why [] is difficult to be defined when to be used for both reading and writing?
How does the definition of class Cref help to solve this issue?
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);}
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您没有定义解决此问题的类
Cref
,那么您必须执行std::map
的操作:这会返回一个引用,必须 由有效的内存位置支持,因此
断言将会成功(意味着
"foo"
现在是映射中的有效键),即使您从未将某些内容分配给m["foo"]
.这种违反直觉的行为可以通过示例中的
Cref
类来修复 - 仅当您分配给引用时,它才可以执行适当的逻辑来创建m["foo"]
,并确保如果您在尝试读取不存在的m["foo"] 时没有执行某些赋值,则
。m.find("foo") == m.end()
同样,在您的 String 类(这是一个引用计数字符串 - 字符串共享其字符串数据,并且当您更改其数据与另一个字符串共享的字符串时,会创建一个新副本),您使用
operator[]
读取字符时必须复制一份。使用Cref
类,可以确保在使用operator[]
写入时只进行复制。If you don't define a class
Cref
that solves this issue, then you have to do whatstd::map
does:This returns a reference, which must be backed by a valid memory location, and therefore
The assertion will succeed (meaning,
"foo"
is now a valid key in the map) even though you never assigned something tom["foo"]
.This counterintuitive behavior can be fixed by the
Cref
class in your example -- it can perform the appropriate logic to createm["foo"]
only when you assign to the reference, and ensure thatm.find("foo") == m.end()
if you didn't perform some assignment when you tried to read the nonexistantm["foo"]
.Likewise, in your
String
class (which is a reference-counted string -- strings share their string data, and a new copy is created when you change a string whose data is shared with another string), you'd have to make a copy when usingoperator[]
to read characters. The use of theCref
class, allows you to ensure that you only make a copy when usingoperator[]
to write.将调用
String::operator [](int)
,然后调用String::Cref::operator =(char)
。但是,
将调用
String::operator [](int)
,然后调用String::Cref::operator char()
。读取时,
String::Cref::operator char
被调用,而写入时,String::Cref::operator =
被调用 - 这允许您区分读取和读取写作。will call
String::operator [](int)
and thenString::Cref::operator =(char)
.However,
will call
String::operator [](int)
and thenString::Cref::operator char()
.When reading,
String::Cref::operator char
is called, and when writingString::Cref::operator =
is called - this allows you to distinguish between reading and writing.这是因为每当您有一个非常量对象时,即使您以只读方式使用它,也会调用非常量
operator[]
。It's because the non-const
operator[]
is called whenever you have a non-const object, even if you're using it in a read-only fashion.