问题
I got a Security Class that has an array of Predictions - Prediction is a Class, which holds only a double.
I want to allow changing the value of the double, but allow only positive values,
and when trying to read the double, if the value is uninitialized (equals -1 in my code) throw exception.
I also have double operator in
Something like that:
class Prediction{
double value;
public:
.....
Prediction::operator double() const {
return this->prediction;
}
Prediction::operator=(const double value){
...
//check value
}
}
class Security{
...
Prediction& Security::operator[](int index){
return predArray[index];
}
}
Prediction *predArray = new Prediction[4];
//default constructor set the value -1;
double a = predArray[0] //should throw an exception, because predArray[0] = -1
predArray[0] = 4; //should be O.K. because I want to change the value
predArray[1] = -4; //should throw exception, because trying to put negative value;
where do I define between reading and writing, because I'm doing different things when reading and writing.
THANKS
回答1:
You cannot do that in operator[]
. There's no way for the operator to know how the value it returns is going to be used. So you have to do this as a function of the returned object. You can handle the assignment to a negative value easy enough, by throwing in the assignment operator of the returned object.
Prediction::operator=(const double value){
if (value < 0)
throw something;
...
}
If you want this statement to throw:
double a = predArray[0];
You will have to do that in your conversion to double operator.
Prediction::operator double() const {
if (value < 0)
throw something;
return value;
}
回答2:
Using a combination of a conversion operator and a conversion constructor you can get this behavior. This sample code should give you an idea on how you need to implement you classes:
class Foo
{
int value;
public:
Foo() { value = -1; }
Foo(int value) {
if (value < 0) cout << "error\n"; else { cout << "ok\n"; this->value = value; }
}
operator int() { if (value < 0) cout << "error\n"; else return value; }
};
class Bar
{
Foo * fooArray;
public:
Bar() { fooArray = new Foo[4]; }
Foo & operator [](int i) { return fooArray[i]; }
};
int main()
{
Bar test;
int foobar = test[0];
test[1] = 4;
test[2] = -4;
cin.get();
return 0;
}
Output:
error
ok
error
回答3:
The central idea is the following: instead of returning a double&
, you can return a proxy with an overloaded operator=
(and everything else which is necessary). Then, the proxy performs the checking.
struct reference_proxy
{
reference_proxy(double &_d) : d(_d) {}
reference_proxy& operator=(double rhs) //operator= throws when rhs<0
{
if(rhs<0.0)
{
std::cout<<"throw exception"<<std::endl;
}
else
{
std::cout<<"ok"<<std::endl;
d = rhs;
}
return *this;
}
operator double () //cast to double gives an error when uninitialized
{
if(d<0.0)
{
std::cout<<"throw exception"<<std::endl;
}
return d;
}
// add further required functions like operator+= etc.
private:
double& d;
};
Then you can use that in your other classes:
struct Prediction
{
operator double& () { return d; }
double d = -1.0;
};
struct Security
{
template<typename ... Args>
Security(Args&& ... args) : v(std::forward<Args>(args) ...) {}
auto operator[](int i)
{
return reference_proxy(v[i]);
}
std::vector<Prediction> v;
};
Application:
int main()
{
Security s(10);
double a = s[0]; //prints "throw exception"
s[0] = 4; //prints "ok"
s[1] = -4; //prints "throw exception"
return 0;
}
DEMO.
Note that this scheme can also be used for much more complex operations. For example: to notify the depending classes in the observer pattern.
回答4:
A few points
The predArray array should be a member of Security (not shown in sample code)
The index access through the [] operator should be on an instance of Security and not predArray. The variable predArray is a raw array of objects, not the object holding your array.
For example:
Security o = new Security();
double a = o[0] //should throw an exception, because predArray[0] = -1
o[0] = 4; //should be O.K. because I want to change the value
o[1] = -4; //should throw exception, because trying to put negative value;
- Add the positive value check on Prediction::operator double() and the Prediction::operator=(const double value) before the return statement;
来源:https://stackoverflow.com/questions/30806786/distinguish-between-read-and-write-using-operator-overloading-in-c