3

I have a class and i overloaded [ operator to use in main. But the problem here is; somewhere in the class in another function. i want to use [ operator like the old style. How can i use them both or how can i modify my overloaded [ parameter ?

Here is overloading part.

T &operator[](int i)
{
if (i < 0 || i >= ArithmeticVector<T>::size())
   throw std::string("Out of bounds!"); //throw std::out_of_range;
else
   return data[i];
};

And here is another function i want to use;

friend ArithmeticVector<T> operator /(const ArithmeticVector<T>& v1, const ArithmeticVector<T>& v2 )
{  
/*Do quick size check on vectors before proceeding*/
ArithmeticVector<T> result(v1.size());
   for (unsigned int i = 0; i < result.size(); ++i)
{
   result[i]=v1[i]/v2[i];
}
   return result;
};

I get an error like error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const ArithmeticVector'

The problem is with this line.

result[i]=v1[i]/v2[i];

overloaded operator didn't like it :/

erenkabakci
  • 442
  • 3
  • 15
  • When you say "the problem is with this line", you get that error when you divide two vectors in main? – tmaric May 19 '13 at 18:38
  • @tomislav-maric yes. When i take `const` from `friend ArithmeticVector operator /(const ArithmeticVector& v1, const ArithmeticVector& v2 )` it compiles but still crashing. – erenkabakci May 19 '13 at 18:40
  • what error do you get when it crashes, a SIGFPE? – tmaric May 19 '13 at 19:11
  • @tomislav-maric its unhandled exception error. i am stuck in a const or non-const elements loop. if i remove const program crashes, if a add const for other overloading this time it doesnt accept. hopeless... – erenkabakci May 19 '13 at 19:35
  • did you try compiling your code without optimization and in full debug mode? Then you can step through the execution of the program and see what happens exactly. If you post this, it will be easier to find the solution to your problem, or you may find it yourself.. – tmaric May 19 '13 at 20:22

2 Answers2

3

I can't understand, what do you mean by I want to use [] operator like the old style, but you should overload operator[] for const version too:

const T& operator[](int i) const
{
    // ...
}

v1 and v2 non-modifiable here, they can't call non-const methods.

awesoon
  • 26,766
  • 9
  • 62
  • 86
  • When i take const from `friend ArithmeticVector operator /(const ArithmeticVector& v1, const ArithmeticVector& v2 )` it compiles but still crashing. Will it work if i write a new method for const one ? and how will i do 2 overloads for same method ? – erenkabakci May 19 '13 at 18:41
  • 1) Probably, no, it shouldn't depends on const qualifiers. 2) How? Hmm... Just write it? – awesoon May 19 '13 at 18:44
  • actually it worked but i am getting unhandled exception error like i miss some constants or doing something wrong. i wrote this btw `T *data2;` `const T& operator[](int i)const { return data2[i]; }` – erenkabakci May 19 '13 at 18:47
  • If you check for bonds in non-const version, you should also check for it in const version(idiomatically). To get more information, try to catch exception with `try`/`catch` blocks. – awesoon May 19 '13 at 18:50
2

You need to overload the access operator for const objects as well, because the r.h.s of the expression result[i] = v1[1] / v2 [i] will evaluate to:

v1.operator[](i) / v2.operator[](i)

and both v1 and v2 are of type const ArithmeticVector<T>& which means that the compiler will try to find the operator[](int) const for both of them (they are constant objects). When you overload the operator for const as advised in the answer above, you can re-use the code in the const operator and just call the operator in the non-const operator by casting away constness of the object. That way you don't have to think about what you implemented in one operator and port it to another, and you don't have to debug your code at two places. Here is the model of your problem (I don't have your implementation of ArithmeticVector, so you have to use the parts of it for your stuff):

template<typename T>
class ArithmeticVector;

template<typename T>
ArithmeticVector<T> operator / (
    const ArithmeticVector<T>& v1, 
    const ArithmeticVector<T>& v2
);

template<typename T>
class ArithmeticVector 
{
    public:

        // Your declaration
        T& operator[](int i)
        {
            // Casting away constness allows code re-use. 
            return const_cast<ArithmeticVector&>(*this).operator[](i);
        }

        // Const declaration:
        T& operator[](int i) const
        {
            // Put your operator code here. 
        }

        friend ArithmeticVector<T> operator / <> (
            const ArithmeticVector<T>& v1, 
            const ArithmeticVector<T>& v2
        );
};

template<typename T>
ArithmeticVector<T> operator / (
    const ArithmeticVector<T>& v1, 
    const ArithmeticVector<T>& v2
)
{
    //ArithmeticVector<T> result(v1.size());
    ArithmeticVector<T> result;

    result[0]=v1[0]/v2[0];

    return result;
};


int main(int argc, const char *argv[])
{

    ArithmeticVector<int> v1, v2, v3; 

    v1 = v2 / v3;

    return 0;
}

There is a great book of Scott Meyers "Effective C++" and there you can read a great description on constness of objects and access operators. There is an answer on SO, that talks about this.

You need to also take care to avoid a Floating Point Exception (division by zero), or SIGFPE, which will happen when v3[i] == 0, which you can do either by stabilizing the result (you loose accuracy):

result[i] = v1[i] / (v2[I] + 1e-15)

or you introduce a test which slows down the divison significantly (like an if testing if v2[i] == 0).

Community
  • 1
  • 1
tmaric
  • 4,835
  • 3
  • 33
  • 65