I want to create a simple 3x3 matrix class and be able to access its contents by the subscript operator. Here's the code:
// Matrix.h
class Matrix {
private:
int matrix[3][3];
public:
int* operator[](const int index) const;
};
// Matrix.cpp
int* Matrix::operator[](const int index) const {
return this->matrix[index];
}
I want to be able to access the elements of the array no matter whether the Matrix's object is const or non-const. But I get the following error from the compiler:
error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
I did some research and I have a hypothesis: maybe, because I have declared this member function as a const function, inside its definition the compiler treats (it masks) all of the the object's non-mutable members as const members, so that would be the reason the compiler says it's an invalid conversion from 'const int*' to 'int*'. My question: Is this hypothesis correct? And if it's not, why does that happens? I think it makes sense and would be a great way of ensuring the const-ness of the 'const Matrix *this' object.
Compiler Info: gcc 5.3.0 downloaded from equation.com
You are absolutely right about the reason why you get the error: inside a member function marked const the compiler implicitly treats all data members of the class as if they were declared with a const qualifier.
The fix is really straightforward - you can override the same operator twice, providing a const and a non-const versions:
class Matrix {
private:
int matrix[3][3];
public:
const int* operator[](const int index) const;
int* operator[](const int index);
};
// Matrix.cpp
const int* Matrix::operator[](const int index) const {
return this->matrix[index];
}
int* Matrix::operator[](const int index) {
return this->matrix[index];
}
The compiler will figure out which overload to call based on the context. It will call const version if the Matrix itself is const, and the non-const version otherwise.
When you declare a class method (and operator is a class method) const, that means you can only call const methods on your class's fields and return only const pointers or references to class fields. In order to compile, you need to make up your mind to have either:
const int* Matrix::operator[](const int index) const { return this->matrix[index]; }
or
int* Matrix::operator[](const int index) { return this->matrix[index]; }
or both.
int* Matrix::operator[](const int index) const {
return this->matrix[index]; }
Here you say you don't modify the state of your object by specifying function as const.
But you are returning a pointer to your instance variable - and through that pointer it is possible to change value of the instance variable of your class (and thus the state).
So you can create a non const version of that operator to avoid that issue.
You are getting this error because you are return a pointer from a const member function (or operator).
const member function and operator should not change any non-mutable member neither return pointers that can change them later.
Make your operator return const pointer rather than pointer.
class Matrix {
private:
int matrix[3][3];
public:
int const* operator[](const int index) const;
};
// Matrix.cpp
int const* Matrix::operator[](const int index) const {
return this->matrix[index];
}
Live Demo
Change this:
int* Matrix::operator[](const int index) const
to this
const int* Matrix::operator[](const int index) const
You cannot return mutable pointer to data member from const function.
Or you may create two versions of operator: const and non const:
const int* Matrix::operator[](const int index) const;
int* Matrix::operator[](const int index);
PS. And anyway it's a very bad practice to return pointer or reference to internal class members.
hope this helps:
#include<iostream>
using namespace std;
class Matrix
{
private:
int matrix[3][3];
public:
const int* operator[](const int index) const;
Matrix(int* value); // need an initializer though :)
};
const int* Matrix::operator[](const int index) const
{
return this->matrix[index];
}
Matrix::Matrix(int* value)
{
for(int i=0; i<3;i++)
{
for (int j=0; j<3; j++)
{
matrix[i][j]= *value;
value++;
}
}
}
int main( void )
{
int arr[] = {1,2,3,4,5,6,7,8,9};
Matrix C(arr);
const int *c;
c = C[0];
for(int i=0;i<3;i++)
{
cout << *c << ends;
c++;
}
return 0;
}
Related
Why is it not possible to assign a value to a reference returned by a const functor?
#include <vector>
template<typename T>
class Test {
public:
T & operator()(size_t index) const {
return A[index];
}
private:
std::vector<T> A{1,2,3};
};
int main() {
const Test<double> test1;
const Test<double> test2;
Test<double> test;
test(0) = test1(0) + test2(1);
}
I get the compiling errors below but I don't understand why the const of the functor is prohibiting the assignment because the functor itself isn't changing its object.
main.cpp:7:12: error: binding value of type 'const
__gnu_cxx::__alloc_traits<std::allocator<double> >::value_type' (aka 'const double') to
reference to type 'double' drops 'const' qualifier
return A[index];
^~~~~~~~
main.cpp:19:7: note: in instantiation of member function 'Test<double>::operator()' requested
here
test(0) = test1(0) + test2(1);
^
If the functor wouldn't be const I would get a compiling error because of the const Test<double> test1, but this is clear to me.
How can I get the code above to be running? I need to use the functor to assign values from const objects.
this in the context of that method is a Test<double> const * which means that this->A is implicitly const. Therefore, A[index] has type double const & which cannot be converted to T & (which is double &).
To put it another way, instance members of a const object are themselves const (unless they are declared mutable).
The correct solution is to have two operator() implementations, one const and one not:
T & operator()(size_t index) { return A[index]; }
T const & operator()(size_t index) const { return A[index]; }
The former will be called on non-const instances and does allow assignment; the latter will be called on const instances and does not allow assignment.
(Demo)
As others have stated, what you have won't work because this is const inside of a method marked as const, so A will also be const, and A[index] will return a const reference, and you can't assign a const reference to a non-const reference, like you are attempting to do.
In this situation, you need two operator() implementations, one that is const and one that is not. The + operator can use the const version to read values from the const objects, and the = operator can use the non-const version to write the result to the non-const object:
template<typename T>
class Test {
public:
const T& operator()(size_t index) const {
return A[index];
}
/* or:
T operator()(size_t index) const {
return A[index];
}
*/
T& operator()(size_t index) {
return A[index];
}
private:
std::vector<T> A{1,2,3};
};
int main() {
const Test<double> test1;
const Test<double> test2;
Test<double> test;
test(0) = test1(0) + test2(1);
}
Live demo
When you have an object of type const Test<...>, the member variable A is also a const object.
That prevents A[0] from be assigned to. A[0] evaluates to a const&, not a non-const&.
In C++, I have some troubles understanding the difference between these 3 ways where const is used :
int get() const {return x;}
const int& get() {return x;}
const int& get() const {return x;}
I'd like to have a clear explanation with examples to help me understand the differences.
Here's the most const example:
class Foo
{
const int * const get() const {return 0;}
\_______/ \___/ \___/
| | ^-this means that the function can be called on a const object
| ^-this means that the pointer that is returned is const itself
^-this means that the pointer returned points to a const int
};
In your particular case
//returns some integer by copy; can be called on a const object:
int get() const {return x;}
//returns a const reference to some integer, can be called on non-cost objects:
const int& get() {return x;}
//returns a const reference to some integer, can be called on a const object:
const int& get() const {return x;}
This question explains a little more about const member functions.
Const references can also used to prolong the lifetime of temporaries.
(1) int get() const {return x;}
We have two advantages here,
1. const and non-const class object can call this function.
const A obj1;
A obj1;
obj1.get();
obj2.get();
2. this function will not modify the member variables for the class
class A
{
public:
int a;
A()
{
a=0;
}
int get() const
{
a=20; // error: increment of data-member 'A::a' in read-only structure
return x;
}
}
While changing the member variable of the class [a] by constant function, compiler throws error.
(2) const int& get() {return x;}
returning the pointer to constant integer reference.
(3)const int& get() const {return x;}
it is combination answer (2) and (3).
Is it still undefined behavior to cast away const from a pointer to an object if only const methods are ever be called after the cast?
I'm trying to implement both an iterator and const_iterator for a class where the dereferenced iterator is a proxy object with a small amount of state and a pointer to the parent object (simplified below)
Although the const qualified proxy only calls const methods on the parent it still requires a non-const pointer in the constructor.
class query {
public:
int get (int r, int c) const;
void set (int r, int c, int v);
class iterator {
iterator (query *q, int r) : m_qry(q), m_row(r) {}
row operator* const () { return row(m_qry, m_row); }
query *m_qry;
int m_row;
};
class const_iterator {
const_iterator (const query *q, int r) : m_qry(q), m_row(r) {}
const row operator* const () {
// protected constructor for row needs cast
return row(const_cast<query *>(m_qry), m_row);
}
const query *m_qry;
int m_row;
};
iterator begin() { return iterator(this, 0); }
const_iterator begin() { return const_iterator(this, 0); }
};
class row {
friend query;
public:
int get (int col) const {
// can be called by both row and const row
return m_qry->get(m_row, col);
}
void set (int col, int v) {
// cannot be called for const row
return m_qry->set(m_row, col, v);
}
protected:
row (query *q, int row) : m_qry(q), m_row(r) {}
private:
query *m_qry;
int m_row;
};
I would prefer to avoid using different classes for the differing iterators as this would require considerable code duplication.
If this is not possible are there any other alternative design patterns with good performance?
In a const method, the this pointer is a const type.
So given that it's implicitly cast back to const, the behaviour is well defined.
I have a class that represents a diagonal matrix. I only store the elements along the diagonal, so I don't waste space with a bunch of 0's. However, I still want to be able to use double brackets to access elements in the array. To get around that, I use an inner class, like this:
template <class T>
class DiagonalMatrix
{
private:
const T ZERO = 0;
int _size;
Vector<T> _data;
class row
{
private:
DiagonalMatrix<T>* _parent;
int _row;
public:
row(DiagonalMatrix<T>* parent, const int row)
: _parent(parent), _row(row) {}
T& operator[](const int i);
};
class const_row
{
private:
const DiagonalMatrix<T>* const _parent;
int _row;
public:
const_row(const DiagonalMatrix<T>* const parent, const int row)
: _parent(parent), _row(row) {}
const T& operator[](const int i) const;
};
friend class row;
friend class const_row;
public:
row operator[] (const int i);
const const_row operator[] (const int i) const;
// other stuff
};
And here are the relevant definitions:
template<class T>
typename DiagonalMatrix<T>::row DiagonalMatrix<T>::operator[](const int i)
{
if (i < 0 || i >= _size)
{
throw IndexOutOfBoundsException(i);
}
return DiagonalMatrix<T>::row(this, i);
}
template <class T>
T& DiagonalMatrix<T>::row::operator[](const int i)
{
if (i < 0 || i >= _parent->_size)
{
throw IndexOutOfBoundsException(i);
}
if (row == col)
{
return _parent->_data[row];
}
// TODO Add a real exception
throw "Cannot modify non-diagonal elements";
}
With similar definitions for the const versions, except the const operator[] returns a reference to the constant ZERO instead of throwing for non-diagonal elements.
So here is my problem: The non-const version is being called even when I don't need to modify anything. For example, this throws my error string:
DiagonalMatrix<double> diag(5);
// fill in the diagonal elements with some values
cout << diag[0][2] << endl;
However, if I remove the non-const versions of the operator, it behaves as expected and outputs a 0.
I've also tried something like:
T& at(const int row, const int col);
const T& at(const int row, const int col) const;
// in main:
cout << diag.at(0, 2) << endl;
But this has the same issue. So I have two questions:
1) Why does C++ choose the non-const version of the function over the const version even when I am not assigning to the result? Doesn't operator<< typically pass the right-hand object by const&?
2) How can I get around this? I'd rather not have separate get() and set() functions if I can help it.
1) Why does C++ choose the non-const version of the function over the const version even when I am not assigning to the result? Doesn't operator<< typically pass the right-hand object by const&?
It choose the non-const version because diag is not a const object.
2) How can I get around this? I'd rather not have separate get() and set() functions if I can help it.
You can define a const refrence to diag and use it to print values:
const DiagonalMatrix<double> &const_diag = diag;
cout << diag[0][2] << endl; // call const version
Or you define a function to print values and pass a const reference in:
void show_diag(const DiagonalMatrix<double> &diag)
{
cout << diag[0][2] << endl; // call const version
}
show_diag(diag);
Let's say I have a container class called MyContainerClass that holds integers.
The [] operator, as you know, can be overloaded so the user can more intuitively access values as if the container were a regular array. For example:
MyContainerClass MyInstance;
// ...
int ValueAtIndex = MyInstance[3]; // Gets the value at the index of 3.
The obvious return type for operator[] would be int, but then the user wouldn't be able to do something like this:
MyContainerClass MyInstance;
MyInstance[3] = 5;
So, what should the return type for operator[] be?
The obvious return type is int& :)
For increased elaboration:
int &operator[](ptrdiff_t i) { return myarray[i]; }
int const& operator[](ptrdiff_t i) const { return myarray[i]; }
// ^ could be "int" too. Doesn't matter for a simple type as "int".
This should be a reference:
int &
class MyContainerClass {
public:
int& operator[](unsigned int index);
int operator[](unsigned int index) const;
// ...
};
Returning a reference lets the user use the result as an lvalue, as in your example MyInstance[3] = 5;. Adding a const overload makes sure they can't do that if MyInstance is a const variable or reference.
But sometimes you want things to look like that but don't really have an int you can take a reference to. Or maybe you want to allow multiple types on the right-hand side of MyInstance[3] = expr;. In this case, you can use a dummy object which overloads assignment:
class MyContainerClass {
private:
class Index {
public:
Index& operator=(int val);
Index& operator=(const string& val);
private:
Index(MyContainerClass& cont, unsigned int ind);
MyContainerClass& m_cont;
unsigned int m_ind;
friend class MyContainerClass;
};
public:
Index operator[](unsigned int ind) { return Index(*this, ind); }
int operator[](unsigned int ind) const;
// ...
};
int&
returning a reference allows you too use the returned value as a left-hand side of the assignment.
same reason why operator<<() returns an ostream&, which allows you to write cout << a << b;