我的类中有const重载方法:
class A{
public:
typedef int data[10];
data& operator[](int index);
const data& operator[](int index) const;
}
这个类正在为它的内部数据实现写时复制。我想,既然我允许直接访问数据,我必须在每次使用operator[]
时创建共享数据的副本(如果它显然是共享的),但不是operator[] const
。然而,即使代码使用operator[]读取数据,但对象本身没有声明为const,它仍然会导致创建副本,因为将使用operator[]。有什么语法可以让我选择调用哪个操作符吗?
Yes: const_cast<A const&>(anAObj)[5]
.
为什么操作符返回data&
而不是引用单个项目的int&
?
话虽如此,你的选择包括:
- 即使不需要,也要拷贝。
- 读取或写入使用操作符,另一个使用命名方法(例如
GetRef
)。 - 在使用点将对象强制转换为
const
:static_cast<const A&>(obj)[index]
。
您需要创建一个Proxy类来替换这两个方法的返回值。然后,在Proxy类中可以适当地处理读取和写入。下面是应该编译的代码来演示这个想法(使用无符号整数数组):
typedef unsigned int UINT;
A类{
class Proxy {
public:
Proxy(const UINT &number): _number(number) {}
const Proxy &operator=(const Proxy &obj) {
cout << "Writting...n";
_number = obj._number;
return *this;
}
operator const UINT &() const {
cout << "Reading...n";
return _number;
}
private:
UINT _number;
};
公众:A(UINT *array): _array(array) {}
Proxy operator[](int index) {
return _array[index];
}
const Proxy operator[](int index) const {
return _array[index];
}
私人:UINT *_array;
};
int main(int argc, char** argv) {
UINT myArray[] = {0, 1, 2, 3, 4};
A a(myArray); // Normal A object
UINT num1 = a[1]; // Reading fine
a[1] = num1; // Writting fine
const A ca(myArray); // Constant A object
UINT num2 = ca[1]; // Reading fine
ca[1] = num2; // Writting NOT fine (compilation error)
return 0;
}
实现data& at(size_t i);
和const data& cat(size_t);
函数,因此您可以在非const对象上调用cat()
来强制返回数据的一致性。
不能,除非将引用/指针强制转换为常量。或者创建一个常量副本。
A a;
const_cast<const A &> (a)[0] /*.foo ()*/;
如果要实现写时复制,则根本不应该定义那些订阅操作符。调用对象x
的订阅方法的const
版本的客户端不允许随后使用该引用来修改x
的组件,但该引用仍应反映其他客户端对x
(该组件)所做的更改。但这种情况不会发生在写时复制策略中,因为更改将发生在与引用点不同的副本上。
两个客户端调用具有相同索引的非const订阅操作符,应该获得对相同 data
对象的(可修改的)引用;但是它们不会,因为在调用订阅操作符时已经生成了两个独立的副本。
相反,您可以使用一个订阅方法按值返回data
。这避免了为x
的组件创建别名的错觉(正如我所说的,在实现写时复制时必须是错觉)。您还可以提供一个方法来修改x
的组件(而不是将此操作拆分为一个订阅,然后对所获得的引用赋值),该方法可以在内部创建一个副本,或者在已经创建副本的情况下直接修改组件。这将对客户端隐藏写时复制实现的使用。
更一般地说,公开对内部对象返回引用的方法,无论是否为const
,都是在公开这些对象是否存在的实现细节。这限制了以后更改实现的自由,例如压缩数据或将其存储在内存以外的其他地方。