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;
}
Related
class Foo
{
public:
const int a;
const int* x;
int* const y;
Foo() : a{ 0 }, y{ new int(20) } {
x = new int(10);
}
};
int main()
{
Foo f;
// f.a = 100; // cannot
f.x = new int(100);
// f.y = new int(100); // cannot
}
When const int a is defined as fields of a class,
it is called a constant member. It must be initialized in the initializer list and cannot be changed afterwards.
How about const int* x (which is the same as int const* x) and int* const y? Which one should be called as a constant member? If "constant member" is defined as field that must be initialized in the initializer list and cannot be changed afterwards, then the constant member is y rather than x. Am I wrong here?
Edit
According to IntelliSense, y is a constant member.
OK. I am sure I am not wrong. I will delete this question shortly. Thank you for your participation!
The "const int* x" is a (non-const) pointer to a const int. Since x is non-const, it need not be initialized upon construction.
Here are some examples:
class C
{
public:
C() :
const_int(1),
const_int_again(2),
const_ptr_to_non_const_int(nullptr),
const_ptr_to_const_int(nullptr)
{}
private:
const int const_int;
int const const_int_again;
const int* ptr_to_const_int; // Doesn't need initialized
int const* ptr_to_const_int_again; // Doesn't need initialized
int* const const_ptr_to_non_const_int;
const int* const const_ptr_to_const_int;
int const* const const_ptr_to_const_int_again;
};
You may find the cdecl.org website helpful.
I've read of the differences between passing by value, passing by reference, and passing (a pointer) by constant reference, yet I'm don't understand the difference between the latter, and just passing a constant pointer. As an example, what is the difference between
int PI = 3;
int* getArg(int* const& x){
x = Π
return x;
}
int main() {
}
and
int PI = 3;
int* getArg(int* const x){
x = Π
return x;
}
int main() {
}
Both of these cause the same error: assignment of read-only parameter 'x'.
If you're clear on passing variables by value and by reference, then try breaking down complex types into parts to help make sense of what's going on:
using PointerToInt = int*;
using ConstPointerToInt = PointerToInt const;
int* getArg_v1(ConstPointerToInt x) {
x = Π // it's const by value so you're not allowed to change it
return x;
}
int* getArg_v2(ConstPointerToInt& x) {
x = Π // it's const by reference so you're not allowed to change it
return x;
}
In this example, is the c-style cast to int& followed by an assignment to kind of hack the interface of class A undefined behavior?
class A
{
public:
A()
: x(0)
{
}
~A()
{
std::cout << x << std::endl;
}
const int& getX()
{
return x;
}
private:
int x;
};
int main()
{
A a;
int& x = (int&)a.getX();
x = 17;
std::cout << x << std::endl;
}
Output:
17
17
If so, what part of the standard can i refer to? Also, is there any reason why this compiles without warnings? (i tested with c++14 on cpp.sh with -Wall, -Wextra and -Wpedantic)
const int& getX() { return x; }
Since this method is not marked const, x is a mutable int. A reference is taken and cast to a const int& at the point of return. Note that although the reference is to a const int, the actual referee int is mutable. This is important.
int& x = (int&)a.getX();
This line takes the returned const int reference and const_cast's it to an int reference. This is legal in c++, full stop. [expr.const.cast]
However, writing through this reference is only legal if the original object being referenced is mutable.
In this case, it is.
You will find the details in [dcl.type.cv]
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.
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.