我想做这样的事情:
class bar{
public:
bool edit;
int foo[];
//If the intention is to change some value in foo:
float & operator [] (int i){
edit = true;
return foo[i];
}
//But if I just want to read
float & operator [] (int i){
return foo[i];
}
}
如果可以的话,我想要正确的方法。
简单的解决方案是存储两个向量,旧的和新的,并每次检查它们。但我想要一个有效的解决方案,而无需手动更改"编辑"每次我改变一些价值。
也许有r值和l值?
编辑: 例如,如果我将检查" foo"的总和,则存储该值,这样我每次想要知道总和时都不必检查foo,只有当foo被修改时。
答案 0 :(得分:1)
C ++中的函数可以标记为const
,表示它不应该更改信息:
class bar{
public:
bool edit;
int foo[];
//If the intention is to change some value in foo:
float & operator [] (int i){
edit = true;
return foo[i];
}
//But if I just want to read
float operator [] (int i) const {
return foo[i];
}
}
另请注意,const
函数的返回类型不同 - 返回float
而不是float&
引用。简单地将函数标记为const
实际上并不会阻止它更改类中的信息。相反,此函数用于const
副本或类本身的引用。
答案 1 :(得分:1)
一般情况下,如你所知,你不能做你想做的事 - 因为C ++不允许你重写引用是否会被修改。我的建议是:
class bar{
public:
bool edit;
int foo[];
// If I just want to read - use index operator.
float operator [] (int i) const {
return foo[i];
}
//If the intention is to change some value in foo:
float & get_ref(int i){
edit = true;
return foo[i];
}
}
换句话说,允许bar_obj[i]
获取只读值,但强制使用get_ref
来获取可修改的引用。这仍然不能阻止某人写作:
std::cout << bar_obj.get_ref(12);
当返回的值不是实际修改时 - 所以不要这样做!
请注意,如果您的真实用例不是浮点数,operator[]
可能会返回const T&
。
答案 2 :(得分:1)
您可以创建一个假装为float
的代理对象,但如果值已更改,则还具有日志记录的附加语义:
#include <cassert>
class bar {
struct Proxy {
Proxy(float &f, bool &edit)
: f{f}
, edit{edit} {}
template <class T>
float &operator=(const T &t) {
edit = true;
f = t;
return f;
}
template <class T>
float &operator+=(const T &t) {
edit = true;
f += t;
return f;
}
template <class T>
auto operator+(const T &t) const {
return f + t;
}
operator float (){
return f;
}
//TODO: add all other relevant operators
private:
float &f;
bool &edit;
};
public:
bool edit{false};
float foo[42]{};
//If the intention is to change some value in foo:
Proxy operator[](int i) {
return {foo[i], edit};
}
//But if I just want to read
float operator[](int i) const {
return foo[i];
}
};
int main() {
bar b;
float f = b[0];
assert(b.edit == false);
b[0] += f;
assert(b.edit == true);
}
存在一些问题,例如实现浮点运算符所需的所有代码以及一些隐式转换被禁用,因为我们添加了用户定义的转换,并且添加0
将设置edit
标志。
此外,我必须更多地考虑如何定义运算符,而不是我为示例在Proxy + Proxy
或与其他类型的交互等边缘情况下展示正确的行为。
答案 3 :(得分:0)
无法保证在通过引用获取时实际设置值。我会明确地创建一个get
和set
函数来编辑变量的状态:
class bar{
public:
bool edit;
int foo[];
float get(int i) { return foo[i]; }
void set(int i, float v) {
edit = true;
foo[i] = v;
}
}
这可以保证所有写入都会被edit
变量反映出来,您无法使用当前方法(或提供的其他参考建议)来确保这一点。
答案 4 :(得分:0)
你可以在const-ness上重载operator []
。 std:: containers这样做。
N.B。您可能不希望将非const引用返回到死值,因为使用该值是未定义的行为。
class bar{
public:
bool edit;
vector<float> foo;
// Mutable float available only to mutable bar's
float & operator [] (int i){
edit = true;
return foo[i];
}
// Has to be const float &, as const bar propogates const-ness to it's members
const float & operator [] (int i) const{
return foo[i];
}
}
答案 5 :(得分:0)
您可以使用静态成员作为伪通知程序来跟踪功能访问。当然,您需要知道必须跟踪哪个功能才能实现这一目标。
所以
class bar{
public:
static int mod_count; //pseudo_notifier
int foo[];
//If the intention is to change some value in foo:
float & operator [] (int i){
mod_count++;
return foo[i];
}
//But if I just want to read
float & operator [] (int i){
return foo[i];
}
int getcount()
{
return mod_count;
}
};
bar::mod_count = 0;
int main()
{
int count = bar::getcount();
bar mybobj;
/*
do whatever operations you plan to do
myobj[someidx] = 29;
*/
if(bar::getcount() > count)
//I know my function has modified the object state
}
答案 6 :(得分:0)
我会使用显式的getter和setter方法(并使数据保密),而不是重载[]运算符:
class bar
{
private:
bool edit;
int foo[];
public:
float get_val(int i) const { return foo[i]; }
void set_val(int i, float v)
{
// Only if new value is different from current value
if (foo[i] != v)
{
edit = true;
foo[i] = v;
}
}
这样就可以确保捕获所有更改,并且没有真正改变任何内容的set
操作没有误报(例如将foo[n]
设置为已包含的相同值) 。通过将您的数据成员设为私有,您可以阻止任何人编写更改foo
但未edit
设置的代码。