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).
Related
I was doing some programs on Object Oreinted Programming in C++.
Here is a brief skeleton of the situation
class coll;
class ele {
private:
int val;
coll* p;
public:
ele(int v, coll* p);
int value() const;
friend bool operator==(const ele& El1, const ele& El2);
friend bool operator<(const ele& El1, const ele& El2);
};
class coll {
private:
set<ele> data;
public:
ele* min() const {
if(size()) {
set<ele>::iterator minIt = min_element(data.begin(), data.end());
ele* ptr = &(*minIt);
return ptr;
}
return nullptr;
}
};
In the min() function, the return type has to be non-const and the function has to be const compulsorily.
I don't know why, but min_element's iterator when de-referenced is giving a const reference. Like, &(*minIt) is a const pointer. But I need a non-const pointer to return.
What can be the reason for this behavior. Thanks in advance.
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&.
What is the difference between this three functions regarding using "const" qualifier
int& func (const int& var)
I know that the const qualifier keep input read-only and can not be changed inside the function.
int const func (int& var)
and this one also return const variable, but what does it mean? it means it can not be changed through the code?
int& func (int& var) const
and what about this one? I have no idea what this means.
int& func (const int& var)
^^^^^^^^^^^^^^
The highlighted part is an argument declaration. The part const int& is the type of the argument variable and var is the name of the variable.
Normally, constness applies to the left, but in this case, it is the left most token of the type. In this exceptional case, it applies to the right instead. To the right is int. Therefore it is a const int. As a whole, the type of the argument is reference to const int.
int const func (int& var)
^^^^^^^^^
The highlighted part is the return type declaration of the function. The return type is a const int object. Although it is well-formed, it never really makes sense to return a const int since the constness is irrelevant to the caller. Most compilers have options to warn in case of such declaration.
Technically, returning a const class object may be different from returning a non-const one, but I have not seen a case where that would be useful.
int& func (int& var) const
Const after the argument list applies to the function itself. A const member function may not be called on a non-const object or reference. The implicit *this argument of the member function will be const. Const qualifier cannot be applied on a non-member function or a static member function.
Regarding old version of the question...
What is the difference between this three functions regarding using "const" modifier
int& func (int& const var)
int& const func (int& var)
These two are ill-formed. Const qualifier cannot apply to a reference (although, you can have a reference to a const type, and such references are colloquially called const references).
You need to read the const quantifiers from right to left to understand them.
so for example int const func(int& var) returns a const int
Here is an example of the use:
#include <stdexcept>
#include <iostream>
int& func(const int& var)
{
std::cout << "func(const int& var) called\n";
throw std::runtime_error("not implemented");
}
int const func(int& var)
{
std::cout << "func(int& var) called\n";
throw std::runtime_error("not implemented");
}
struct A {
int& func(int& var) const
{
// i = 2; illigal since const function
std::cout << "func(int& var) const called\n";
throw std::runtime_error("not implemented");
}
int i;
};
int main()
{
try
{
const int i = 1;
func(i);
}
catch (std::exception) {}
try
{
int j = 2;
func(j);
}
catch (std::exception) {}
try
{
A a;
int k = 2;
a.func(k);
}
catch (std::exception) {}
}
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;
}
I have seen the following code:
template <class T>
class Type {
public:
Type() {}
T& operator=(const T& rhs) {value() = rhs; return value();}
T& value() {return m_value;}
T value() const {return m_value;}
private:
T m_value;
};
Why does the compiler not complain about
T& value() {return m_value;}
T value() const {return m_value;}
and how to know which one is invoked?
The two functions are actually not the same. Only the second function is declared as a const member function. If the object that the member is called from is const, the latter option is used. If the object is non-const, the first option is used.
Example:
void any_func(const Type *t)
{
something = t->value(); //second `const` version used
}
void any_func2(Type *t)
{
something = t->value(); //first non-`const` version used
}
If both functions were declared non-const or both were declared const, the compiler would (should, anyway) complain.
Why does the compiler not complain about
Because the const counts for a different function signature. Your assumption the function signatures are identical is wrong.
The function marked as const will be invoked for any const instance or reference of Type<T>.
and how to know which one is invoked?
Put a cout statement in the functions and test the following cases:
template <class T>
class Type {
public:
Type() {}
T& operator=(const T& rhs) {value() = rhs; return value();}
T& value() {
std::cout << "non const version" << std endl;
return m_value;
}
T value() const {
std::cout << "const version" << std endl;
return m_value;
}
private:
T m_value;
};
int main() {
Type<int> t;
t.value();
Type<int> rt = t;
rt.value();
Type<int>* pt = &t;
pt->value();
const Type<int> ct;
ct.value();
const Type<int>& crt = t;
crt.value();
const Type<int>* pct = &t;
pct->value();
}
Your assignment operator will call the non const version.
The const version should better look like
const T& value() const {
std::cout << "const version" << std endl;
return m_value;
}
because you can't always rely on RVO (return value optimization), and extra copies might be taken (especially for older compiler implementations).
Also note the assignment operator should return a reference to the current instance:
Type& operator=(const T& rhs) {value() = rhs; return *this;}
A couple of words on functions resolution priority. Compiler distinguishes between const/non const functions on following way:
If a class has only const function with given name and argument list, it will be called for constant and non-constant objects alike. After calling this function, object will 'assume' constness (even if it was not const), meaning that the function can only call other const functions.
If a class has only non-const function, it will be called for non-const objects. Attempt to call this function for const objects will lead to compilation error.
If a class has both functions available, const version will be used for const objects, non-const version will be used for non-const objects.
Thanks to #owacoder for pointing my attention to initial mixup in the description.