Multiple operator[] overloads - c++

Take a look at this simple array class
class Array {
const unsigned int _size;
int _array[100];
public:
Array() : _size(100) {
for(unsigned int i = 0; i < _size; i++)
_array[i] = 0;
}
int& operator[](unsigned int index) {
cout << "normal operator[].\n";
return _array[index];
}
const int& operator[](unsigned int index) const {
cout << "const operator[].\n";
return _array[index];
}
};
int main()
{
Array a;
a[3] = 1;
cout << a[3] << "\n";
system("pause");
return 0;
}
The "normal operator[]" line is executed twice, though I would expect the second call (cout << a[3] << "\n";) to be using the const version of the overloaded operator, because it doesn't change the array itself.
Why is that? Is there a way to force the const version to be called as I wish?

When you have an overloaded const version of a method, the const version will be called when the object is const. For example:
#include <iostream>
using namespace std;
class MyClass
{
public:
void foo()
{
cout << "foo()" << endl;
}
void foo() const
{
cout << "foo() const" << endl;
}
};
int main()
{
MyClass a;
const MyClass b;
a.foo();
b.foo();
return 0;
}
will call the normal foo() for the object a, and the const version for the object b.
In your case, you just have to avoid trying to assign to the const version. For example:
Array a;
const Array b;
a[3] = 1;
// b[3] = 1; // error
cout << a[3] << "\n";
cout << b[3] << "\n";
works fine. But if you try to make the assignment to b, you get a compile error.

std::ostream &operator<<(int x) doesn't take its parameter as const (because const isn't useful when passing by value), so the non-const operator[] can be called.
So, when will const operator[] be called?
It is true that a const vector variable declaration is almost always useless aside from some edge cases. The primary reason const operator[] is important, and the most often you will see it used, is calling it on a reference parameter.
int readStuff(const std::vector<int> &dontMutateMe) {
return dontMutateMe[42]; // const
}
Constant reference parameters are valuable, and this code wouldn't work without const operator[].

Related

C++ pass a function in a class by reference

I'm trying to pass a reference to a function in a class but am having trouble figuring out how to do it. So say I have a class test defined as such
#include <iostream>
class test {
public:
test () {};
~test () {};
void setA (int);
int getA (void);
private:
int a;
};
void test::setA (int A) { a = A; }
int test::getA (void) { return a; }
using namespace std;
int main ()
{
test T;
T.setA(5);
cout << "a = " << T.getA() << endl;
return 0;
}
That works fine but if I want to pass the values by reference
#include <iostream>
class test {
public:
test () {};
~test () {};
void setA (int);
int & getA (void);
private:
int a;
};
void test::setA (int & A) { a = A; }
int & test::getA (void) { return a; }
using namespace std;
int main ()
{
test T;
T.setA(5);
cout << "a = " << T.getA() << endl;
return 0;
}
I cannot figure out how to configure setA to pass by reference.
There are two issues with the code. First, the definition of setA does not match the declaration. You must make the declaration take in a reference as a parameter.
Change this:
void setA (int);
To this:
void setA (int&);
The second issue is that you are trying to pass an r-value (5) as a reference. You must pass in an l-value. You can do that by creating an int first and then passing that by reference:
int i = 5;
T.setA(i);
Full example:
#include <iostream>
class test {
public:
test () {};
~test () {};
void setA (int&);
int & getA (void);
private:
int a;
};
void test::setA (int & A) { a = A; }
int & test::getA (void) { return a; }
using namespace std;
int main ()
{
test T;
int i = 5;
T.setA(i);
cout << "a = " << T.getA() << endl;
return 0;
}
When you pass something by reference to a function in C++, the function does not keep the parameter in memory automatically. Thus, you have to declare it before so that it stays in memory throughout the entire function.
The 5 you tried to pass as a reference would go out of scope and get destroyed as soon as the function starts. The declared i variable is instead destroyed at the end of the main function.
The reason is because in order to pass by reference, you must have an lvalue, which is a fancy way of saying something that persists beyond a single use.
If you created an int variable, you would be able to pass it in by reference. In the code above, you attempted to pass in a raw integer value (5), which fails, since the compiler is expecting a reference to an int, not a raw integer value.
The following code would work:
int main ()
{
test T;
int myVariable = 4; // Need an actual variable to pass by reference.
T.setA(myVariable);
cout << "a = " << T.getA() << endl;
return 0;
}
However, if you want your function to take raw integer values like you showed in your second example, you must have a function definition like your first example, where all the function takes is an integer. Hope this helps!
Maybe you could try this:
#include <iostream>
class test {
public:
test() {};
~test() {};
void setA(int&&); // requires at least C++11
void setA(int&);
int & getA(void);
private:
int a;
};
void test::setA(int && A) { a = A; }
void test::setA(int&A) { a = A; }
int & test::getA(void) { return a; }
using namespace std;
int main()
{
test T;
int i = 5;
T.setA(i);
cout << "a = " << T.getA() << endl;
T.setA(8);
cout << "a = " << T.getA() << endl;
return 0;
}
In the example, int& passes a l-value while int&& passes a r-value as a reference.

function overload of a constant object

struct A {
void foo(int i, char& c) {
cout << "foo int char&" << endl;
}
void foo(int& i, int j) const {
cout << "const foo int& int" << endl;
}
};
int main() {
A a;
const A const_a;
int i = 1;
char c = 'a';
a.foo(i,i);
}
Will be printed:
const foo int& int
I dont understand why.
Why "const foo int& int" wont be printed?
I thought that constant Object can only call constant methods, and none const can call none const.
You misunderstood member-const.
A normal object can have any member function invoked on it, const or otherwise.
The constraint is that your const_a would not be able to have the non-const member function invoked on it. Unfortunately, you did not test that.

C++ operator [] overload not responding

I've created the class array and something is going weird.. the class is the following:
class array
{
private:
int *a_;
size_t size_;
public:
array();
array(const size_t);
array(const arreglo &);
~array();
int const &operator[](size_t)const;
int &operator[](size_t);
array const &operator=(const array&);
bool empty()const;
};
The overload's implementation of [] are:
int const &array::operator[](size_t index)const
{
std::cout << "getter" << std::endl;
return a_[index];
}
int & array::operator[](size_t index)
{
std::cout << "setter" << std::endl;
return a_[index];
}
The way i'm testing the code is in this main:
int main()
{
array a(7);
a[0] = 3;
a[1] = 6;
a[2] = a[0] + a[1];
array b = a;
std::cout << b[2] << std::endl;
return 0;
}
The problem is that the opertar [] is just using the getter version and prints through cout "setter" and never "getter".
What is going wrong?
Thinking of them as "getter" and "setter" variants is a mistake. The difference between the two is merely the cv-qualification of the function and the return type. They are both getters. More importantly, you are returning reference types.
References tend to decay, in this case to a mutable int, therefore the compiler is more likely to accept a non-const function call.
a[0];
The default evaluation of this statement is an integer value, not a reference, so that you can for instance do:
if (a[0])
and this is predicate on the value at a[0] rather than the reference (evaluating the reference would always be true and not very helpful).
Remember that when references are used in most statements they decay to the referred value.
int v = a[0]; // no error, even tho v's type is not int&
int& vr = a[0]; // decays to the value a references
// then takes a reference of that
(Note: that the compiler may elide the implied set of operations to simply capture or imply the original reference in the second statement).
So the code
a[2] = a[0] + a[1]
It starts by getting the values from a[0] and a[1], knowing that it wants to do math, so the easiest way for it to do this is:
int a1 = a.operator[](1);
int a0 = a.operator[](0);
int& dest = a.operator[](2);
dest = a0 + a1;
If you want const, you're going to need either a const/const-ref to an array or to specify that you want a const ref:
const int& ar = a[0];
#include <iostream>
struct array
{
int i = 0;
array() {}
const int &operator[](size_t) const { std::cout << "const int[]\n"; return i; }
int &operator[](size_t) { std::cout << "int[]\n"; return i; }
};
int main()
{
array a;
a[0];
int v1 = a[0];
const int v2 = a[0];
std::cout << "refs\n";
int& v3 = a[0];
const int& v4 = a[0];
std::cout << "const array\n";
const array b;
b[0];
int v5 = b[0];
const int v6 = b[0];
std::cout << "refs\n";
//int& v7 = b[0]; // would produce a compile error
const int& v8 = b[0];
}
See http://ideone.com/7EYGYj
In short
void f(const array& b){
std::cout << b[2] << std::endl;
}
b is required to be const. All that is available is the const functions.
In your example it is a "read" but b is not const so the non-const is called. It is using the "setter" as the getter.

Pointer to int. C++

I need to pass to function pointer to int.
Now if I want to pass 5 I'm doing it like this:
int * i = NULL;
int b = 5;
i = &b;
Is there any better way to write it shorter?
I want to pass bytes that are in i int to this function:
void Write2Asm(void* pxAddress, BYTE * MyBytes, int size)
You can just pass &b to the function; no need for an intermediate pointer variable.
Why to create a pointer variable?. Why can't you do it like this?.
int b = 5;
func(&b)
void f(int *i)
{
//...
}
int b = 5;
f(&b);
is enough!
There are a few old C APIs that always take arguments by pointer, even if they're effectively read-only booleans etc.. I'm not recommending it - more for interest's sake - but if you want to go the whole hog you could do something hackish like:
#include <iostream>
struct X
{
X(int n) : n_(n) { std::cout << "X()\n"; }
~X() { std::cout << "~X()\n"; }
operator int&() { return n_; }
operator const int() const { return n_; }
int* operator&() { return &n_; }
const int* operator&() const { return &n_; }
int n_;
};
// for a function that modifies arguments like this you'd typically
// want to use the modified values afterwards, so wouldn't use
// temporaries in the caller, but just to prove this more difficult
// case is also possible and safe...
void f(int* p1, int* p2)
{
std::cout << "> f(&" << *p1 << ", &" << *p2 << ")\n";
*p1 += *p2;
*p2 += *p1;
std::cout << "< f() &" << *p1 << ", &" << *p2 << "\n";
}
int main()
{
// usage...
f(&X(5), &X(7));
std::cout << "post\n";
}
Crucially, the temporaries are valid until after the function call f(...) exits.

Const operator overloading problems in C++

I'm having trouble with overloading operator() with a const version:
#include <iostream>
#include <vector>
using namespace std;
class Matrix {
public:
Matrix(int m, int n) {
vector<double> tmp(m, 0.0);
data.resize(n, tmp);
}
~Matrix() { }
const double & operator()(int ii, int jj) const {
cout << " - const-version was called - ";
return data[ii][jj];
}
double & operator()(int ii, int jj) {
cout << " - NONconst-version was called - ";
if (ii!=1) {
throw "Error: you may only alter the first row of the matrix.";
}
return data[ii][jj];
}
protected:
vector< vector<double> > data;
};
int main() {
try {
Matrix A(10,10);
A(1,1) = 8.8;
cout << "A(1,1)=" << A(1,1) << endl;
cout << "A(2,2)=" << A(2,2) << endl;
double tmp = A(3,3);
} catch (const char* c) { cout << c << endl; }
}
This gives me the following output:
NONconst-version was called - - NONconst-version was called - A(1,1)=8.8
NONconst-version was called - Error: you may only alter the first row of the matrix.
How can I achieve that C++ call the const-version of operator()? I am using GCC 4.4.0.
The overloading looks fine but you never call it on a const object. You can try this:
void foo(const Matrix& A) {
cout << "A(1,1)=" << A(1,1) << endl;
}
Matrix A(10,10);
foo(A);
This gives you:
- const-version was called - A(1,1)=0
The object you are calling the method on must be const, e.g.
cout << "A(2,2)=" << (*static_cast<const Matrix*>(&A))(2,2) << endl;
Generally, you can't call a const or non-const version of a function depending on what you do with the return value. If you want to emulate similar functionality, you can try returning some proxy that will switch the behaviour depending on what you do with it:
class Proxy
{
Matrix& m;
int x, y;
public:
...
// mutating operations
operator double&() { check(); return m.index(x,y); }
double& operator=(double d) { check(); return m.index(x,y)=d; }
// ... other mutating operations (+=, ...) analogously
// nonmutating ops
operator double() { return m.const_index(x, y); }
operator const double&() // ... same
};
Proxy Matrix::operator(int x, int y)
{
return Proxy(*this, x, y);
}
Assuming check() is your check for legal mutation (could be integrated in index()) and index() and const_index() are methods in Matrix that give a reference or const reference to a particular place.
Use const_cast<>() or make your instance const.
I'm guessing maybe you want to be sure the operator returns a const double? Maybe you should just provide the const version, not the other one.
You have different methods with different functionality, so give them different names. Then you don't need to have a const object just to call what you want.
You can still make operator() const call the alternative function in case you do happen have a const object. But the alternative functionality should be put in a function with a descriptive name.
As for getting a const handle to an object, use static_cast< const Matrix & >( A ).