For a project I'm trying to create a vector class with vector function. I'm trying to add a vector addition function by overriding the += addition assignment. Because I don't want the += function to change the value to add I want to pass that value as a const reference.
My code:
Vector2D.h
#pragma once
class Vector2D
{
private:
int m_x, m_y;
public:
Vector2D(int x, int y);
int getX();
int getY();
void setX(int x);
void setY(int y);
Vector2D& operator+=(const Vector2D&);
};
Vector2D.cpp
#include "Vector2D.h"
Vector2D::Vector2D(int x, int y)
{
m_x = x;
m_y = y;
}
int Vector2D::getX()
{
return m_x;
}
int Vector2D::getY()
{
return m_y;
}
void Vector2D::setX(int x)
{
m_x = x;
}
void Vector2D::setY(int y)
{
m_y = y;
}
Vector2D& Vector2D::operator+=(const Vector2D& toAdd)
{
m_x += toAdd.getX();
m_y += toAdd.getY();
return *this;
}
But I get the errors:
the object has type qualifiers that are not compatible with the member
function "Vector2D::getX"
and
int Vector2D::getX(void)': cannot convert 'this' pointer from 'const
Vector2D' to 'Vector2D &'
I tried chaining the functions that return x and y to const:
const int Vector2D::getX()
const int Vector2D::getY()
but this won't solve the error. Remove the const from the parameter solves all errors and results in working code.
How should I change my code to make sure the value passed to the += operator can't be changed (for example by calling setY(100) on the object passed)?
Make Vector2D::getX() const as well. Otherwise you can't call it on an object you have by const reference.
Your attempt at adding const was applied to the functions return value, not the this pointer
const int Vector2D::getX()
Is a function on a non-const object that returns a const int.
int Vector2D::getX() const
Is a function on a const object.
This is one reason why it is often said that "a leading const is misleading".
getX() and getY() are non-const member functions, which can't be called with const object. Since they won't modify any members of class Vector2D, you should mark them as const member function, like
int Vector2D::getX() const
Note the position of const, which should be put at the end of the function declaration, means the function won't modify any members (except for mutable ones) of the class. const int Vector2D::getX() means the function will return a constant, it has nothing to do with the characteristic of the member function. In fact, return a constant build-in type doesn't make much sense, from the aspect of the caller side, it doesn't make any difference.
What you are looking for is : Constant Member Functions.
int Vector2D::getX() const
The const after the argument list in the function declarations indicates that the function does not modify the state of a object.
A const member function can be invoked for both const and non-const objects, whereas a non-const member function can be invoked only for non-const objects.
In your case, toAdd is const.
Related
I didn't find any topics related to mutable const on SO. I have reduced code to minimal working code (on visual studio). If we uncomment //*data = 11;, the compiler complains about const-ness. I wonder how mutable const works.
class A
{
public:
void func(int & a) const
{
pdata = &a;
//*pdata = 11;
}
mutable const int * pdata;
};
int main()
{
const A obj;
int a = 10;
obj.func(a);
}
This example is a little confusing, because the mutable keyword is not part of the type specifier const int *. It's parsed like a storage class like static, so the declaration:
mutable const int *pdata;
says that pdata is a mutable pointer to a const int.
Since the pointer is mutable, it can be modified in a const method. The value it points to is const, and cannot be modified through that pointer.
You are correct in understanding that a mutable const class member is meaningless. Your example is more demonstrating a quirk of how const works with pointers.
Consider the following class.
class A {
const int * x; // x is non-const. *x is const.
int const * y; // y is non-const. *y is const.
int * const z; // z is const. *z is non-const.
};
So const has different meanings depending on where you write it.
Since x and y are non-const, there's no contradiction in making them mutable.
class A {
mutable const int * x; // OK
mutable int const * y; // OK
mutable int * const z; // Doesn't make sense
};
mutable const sounds like an oxymoron, but it actually has a perfectly sensible explanation. const int * implies that the pointed-to integer value cannot be changed through that pointer. mutable means that the pointer itself can be changed to point to another int object, even if the A object to which the pdata member belongs it itself const. Again, the pointed to value can't be changed through that pointer, but that pointer itself can be reseated.
Your code fails when the assignment statement is uncommented because that assignment violates your promise not to modify the pointed to value (the const int * part).
I am beginner in cpp language.
Recently I saw in a many classes declare twice the same function with a little different such as:
int& operator[](size_t i) {
assert(i<size());
return _buf[i];
}
const int& operator[](size_t i) const {
assert(i<size());
return _buf[i];
}
What is the different between the function? why I need the first one? and in which cases the first function will be work and in which cases the second function will be work?
On of those is const the other isnt. Let me put it in some context:
struct Foo{
int value = 0;
int& operator[](size_t i) {
std::cout << "non-const\n";
return value;
}
const int& operator[](size_t i) const {
std::cout << "const\n";
return value;
}
};
The const version will be called on const instances while the non-const will be called on non-const instances. E.g.
int main(){
Foo f;
int x = f[0];
f[0] = 3; // OK
const Foo g;
int x = g[0];
//g[0] = 3; // NOT OK
}
...will print
non-const
const
Indeed both methods should be the same and the major difference is the const version returning a const reference while the non-const returns a reference that allows to modify the value.
As you correctly observed, apart from the constness and the return type, the two are identical. To avoid duplicate code, sometimes it can make sense to use a small trick and write the const version in terms of the non-const:
const int& operator[](size_t i) const {
std::cout << "const\n";
return const_cast<Foo*>(this)->operator[](i);
}
See here for the full example.
Usually you don't want to let users change your objects somehow if they are marked as const.
It means that if you have a class which provides operator[], you don't want to let users change the internal state of objects of this class via operator[] if these objects are const.
That's why you have two overloads. If the object is const, then the version
const int& operator[](size_t i) const
is called. This version returns const int&, so you can't do any modification.
In opposite, if the object is not marked as const, then
int& operator[](size_t i)
is called and you are free to modify the internal state of the object via the reference returned.
The differences are the const keyword:
int& operator[](size_t i) { (1)
const int& operator[](size_t i) const { (2)
The first function return a reference to the object, which means that you can modify the object (for example by doing foo[0] = bar.
The second use the const keyword twice: const int& means that you return a const reference that you can't modify. The second const is here to specify that this function will not modify the object.
You need those two version because (1) is used when you want to modify an element of the collection and (2) is used on const object:
you can do this:
void foo(std::vector<int> const& v) {
int j = v[0];
}
because vector as an operator that look like (2)
The first overload states that the subscript operator can modify internals of the class instance, the later states that internals of the class instance are read-only and thus, can't be modified.
Effectively, it means that this pointer points to either const or non-const object.
Previously:
You tagged your question with C which is not correct, as C does not offer any class member functions and thus AFAIK, const after the global function declaration is illegal.
It means your class is providing the support for two things,
Non Const Object
Const Object
int& operator[](size_t i) will be called for Non const object, because there is no const qualifier at the end.
const int& operator[](size_t i) const will be called for const object, because there is const qualifier at the end.
Here is my code :
class X
{
public:
X():_x(5){}
void GetVal(int & oVal)
{
oVal = _x;
}
private:
int _x;
};
class Y
{
public:
X * const GetX()
{
return &_x;
}
private:
X _x;
};
int main()
{
Y y;
X * p = y.GetX();
int * pInt = new int[2];
p->GetVal(pInt[0]);
}
In the last line of main, I get an error
Incorrect access of a member from const-qualified function
This error is observed only when the code is compiled on a sun solaris system and doesn't happen on windows or aix system. Any idea why?
Also the strangest thing is that the error is gone if I replace pInt[0], with a simple integer (int a = 0; p->GetVal(a))
The const in X * const GetX() will be ignored, because the result of the function call is an rvalue and rvalues of non class type cannot be const according to c++ const member function that returns a const pointer.. But what type of const is the returned pointer?.
Are you sure you didn't mean to write:
const X * GetX() const
{
return &_x;
}
that is, you change it from returning a constant pointer to variable date into a variable pointer to constant data, and you declare GetX() to be a constant member function, that is a member function that can be used on constant instances of Y: const Y y;
Furthermore in class X, you can change GetVal() to
void GetVal(int & oVal) const
{
oVal = _x;
}
This question already has answers here:
Meaning of 'const' last in a function declaration of a class?
(12 answers)
Closed 7 years ago.
In C++ sometimes I see declarations like below:
return_type function_name( datatype parameter1, datatype parameter2 ) const
{ /*................*/}
What does this const type qualifier exact do in this case?
The const qualifier at the end of a member function declaration indicates that the function can be called on objects which are themselves const. const member functions promise not to change the state of any non-mutable data members.
const member functions can also, of course, be called on non-const objects (and still make the same promise).
Member functions can be overloaded on const-ness as well. For example:
class A {
public:
A(int val) : mValue(val) {}
int value() const { return mValue; }
void value(int newVal) { mValue = newVal; }
private:
int mValue;
};
A obj1(1);
const A obj2(2);
obj1.value(3); // okay
obj2.value(3); // Forbidden--can't call non-const function on const object
obj1.value(obj2.value()); // Calls non-const on obj1 after calling const on obj2
$9.3.1/3 states-
"A nonstatic member function may be declared const, volatile, or const volatile. These cvqualifiers affect the type of the this pointer (9.3.2). They also affect the function type (8.3.5) of the member function; a member function declared const is a const member function, a member function declared volatile is a volatile member function and a member function declared const volatile is a const volatile member function."
So here is the summary:
a) A const qualifier can be used only for class non static member functions
b) cv qualification for function participate in overloading
struct X{
int x;
void f() const{
cout << typeid(this).name();
// this->x = 2; // error
}
void f(){
cout << typeid(this).name();
this->x = 2; // ok
}
};
int main(){
X x;
x.f(); // Calls non const version as const qualification is required
// to match parameter to argument for the const version
X const xc;
xc.f(); // Calls const version as this is an exact match (identity
// conversion)
}
It means that it doesn't modify the object, so you can call that method with a const object.
i.e.
class MyClass {
public:
int ConvertToInteger() const;
};
Means that if you have
const MyClass myClass;
you can call
int cValue = myClass.ConvertToInteger();
without a compile error, because the method declaration indicates it doesn't change the object's data.
How this code modifies a value in a const function:
#include<iostream>
using namespace std;
class Y;
class X{
public:
void access(Y &y) const;
};
class Y{
int d;
public:
friend void X::access(Y &y) const;
Y(){d=0;}
};
void X::access(Y &y) const
{
cout<<"Y is "<<y.d<<endl;
y.d=1;
cout<<"Y is "<<y.d<<endl;
}
int main() {
X x;
Y y;
x.access(y);
}
And this code gives an error:
#include<iostream>
using namespace std;
class Y{
int d;
public:
void set() const{d=0;}
};
int main() {
Y y1;
return 0;
}
Because in your first example:
void X::access(Y &y) const;
the const tells the compiler that the function won't modify the class X object that the implicit this parameter points to. The class Y object that's passed as a reference isn't const.
In the second example, the set() function is a member of class Y:
void set() const
and it's declared such that the implicit this parameter pointing to the Y object is a const pointer (so that object can't be modified).
If you want X::access() to not be permitted to modify the Y object passed to it, change the declaration to:
void X::access(Y const& y) const;
Because inside a const function, only *this is const, not the parameters passed to the function or anything else.
In the first example, the const-qualifier on X::access(Y &y) const means that the X object on which it is called cannot be modified. Since the Y parameter is taken by non-const reference, it can be modified from within the function.
In the second example, the const-qualifier on Y::set() const means that the Y object on which it is called cannot be modified, hence why you cannot modify the non-mutable member variable d.
a member function being const only promises not to change any members of the class it belongs to (execpt if they are declared mutable).
In the first example, Y.d is being modified in method X::access. The method does not modify any members of X itself so is perfectly sane.
In the second example however, the Y::set() method is declared const so it cannot change Y::d.
Next time, please post the code here instead of providing a link.