2011-04-29 65 views
0

我有我的类常量,重载的方法:C++非const const的重载的方法选择

class A{ 
    public: 
    typedef int data[10]; 

      data& operator[](int index); 
    const data& operator[](int index) const; 
} 

这个类实现写入时复制了它的内部数据。我想,因为我允许直接访问数据,所以我必须在每次使用operator[]而不是operator[] const时创建共享数据的副本(如果它明显共享)。但是,即使代码使用operator []来读取数据,但对象本身并没有声明为const,它仍然会导致创建副本,因为将使用operator []。有没有什么语法可以让我选择我打电话给哪些运营商?

+1

如果您允许人们保存返回的参考资料并在以后使用,那么您必须在返回参考资料后禁用将来的共享。 – 2011-04-29 14:13:38

回答

2

是:const_cast<A const&>(anAObj)[5]

0

不,除非您将参考/指针转换为常量。或者创建一个不变的副本。

A a; 
const_cast<const A &> (a)[0] /*.foo()*/; 
+0

嗯,“不,除非”相当于“是”,不是吗? ;) – ereOn 2011-04-29 14:06:04

+0

@ereOn:我认为这取决于。在这种情况下,我的意思是听起来更像是一个连接,突出了异常的可能性,而不是一个完善的规则,这意味着有这样的语法,但是在代码中使用它将不会让用户开心。实际上,我在回答写回答时的想法是,我将实现具有不同接口的写入时拷贝,其中数据代理始终保持不变,除非复制和基础数据是可变的。但是这太想了,所以我决定简单陈述“坏”的语法,并摆脱它,但你抓住了我:-D – 2011-04-29 14:16:52

1

为什么运营商返回一个data&而非int&引用单个项目?

话虽这么说,你的选择包括:

  • 永远做哪怕原来是不需要的副本。
  • 使用操作员进行读取或写入,并为另一个使用命名方法(例如GetRef)。
  • 在使用地点将对象投射到conststatic_cast<const A&>(obj)[index]
+0

我正在返回'数据&'所以我可以有支架操作符的二维数组他们在我的对象像'A a;''a [1] [2] = 3;'。 – 2011-04-29 14:19:16

0

实施data& at(size_t i);const data& cat(size_t);功能,这样你就可以在非const对象调用cat()执行返回的数据常量性。

+0

这是我很乐意做的事情,如果不是我使用'operator []'的事实,并且因此不能向名称添加字母或任何内容。 – 2011-04-29 14:17:49

1

您需要创建一个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主(INT ARGC,字符**的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; 

}

+0

想法很好,但是从我的代码中可以看到,我希望可以使它与多维数组一起工作 - 它仍然是可能的,但随着维数的增长,它变得凌乱,似乎不容易泛化到n维。 (用我的方法,我可以将数据输入为n-1维数组,然后将我的对象视为n维数组)。 – 2011-06-12 02:02:27

0

如果要实现写入时复制,那么你不应该在所有定义这些订阅的运营商。如果客户端调用对象x的订阅方法的const版本,则不允许随后使用该引用修改x的组件,但引用仍应反映其他客户端对该组件的更改(该组件)x。但是他的写作策略是不会发生的,因为这种变化将发生在与参考点不同的副本上。

另外两个调用具有相同索引的非const订阅操作符的客户端应获得(可修改的)对的相同引用data对象;但他们不会,因为在订阅操作员被调用时会创建两个单独的副本。

取而代之,您可以使用按值返回data的订阅方法。这避免了创建获得x的组件的别名的错觉(正如我认为必须是当写入复制被实现时的虚幻)。您还可以提供一种修改x组件的单一方法(而不是将此操作拆分为订阅,然后将其分配给所获得的引用),该方法可以在内部创建副本,也可以仅在此副本上修改组件已经制成。这会隐藏客户端使用写入时复制实现。

更一般地说,暴露返回对内部对象的引用的方法,不管const是否暴露了这些对象完全存在的实现细节。这限制了稍后更改实现的自由度,例如压缩数据或将其存储在其他地方而不是内存中。

相关问题