Why can't I use the function ColPeekHeight() as an l-value?
class View
{
public:
int ColPeekHeight(){ return _colPeekFaceUpHeight; }
void ColPeekHeight( int i ) { _colPeekFaceUpHeight = i; }
private:
int _colPeekFaceUpHeight;
};
...
{
if( v.ColPeekHeight() > 0.04*_heightTable )
v.ColPeekHeight()-=peek;
}
The compiler complains at v.ColPeekHeight()-=peek. How can I make ColPeekHeight() an l-value?
Return the member variable by reference:
int& ColPeekHeight(){ return _colPeekFaceUpHeight; }
To make your class a good one, define a const version of the function:
const int& ColPeekHeight() const { return _colPeekFaceUpHeight; }
when I declare the function with the
two consts
When you want to pass an object into a function that you don't expect it to modify your object. Take this example:
struct myclass
{
int x;
int& return_x() { return x; }
const int& return_x() const { return x; }
};
void fun(const myclass& obj);
int main()
{
myclass o;
o.return_x() = 5;
fun(o);
}
void fun(const myclass& obj)
{
obj.return_x() = 5; // compile-error, a const object can't be modified
std::cout << obj.return_x(); // OK, No one is trying to modify obj
}
If you pass your objects to functions, then you might not want to change them actually all the time. So, to guard your self against this kind of change, you declare const version of your member functions. It doesn't have to be that every member function has two versions! It depends on the function it self, is it modifying function by nature :)
The first const says that the returned value is constant. The second const says that the member function return_x doesn't change the object(read only).
It can be rewritten like:
class View
{
public:
int GetColPeekHeight() const { return _colPeekFaceUpHeight; }
void SetColPeekHeight( int i ) { _colPeekFaceUpHeight = i; }
private:
int _colPeekFaceUpHeight;
};
...
{
cph = v.GetColPeekHeight();
if ( cph > 0.04 * _heightTable )
v.SetColPeekHeight( cph - peek );
}
Related
When I was checking some code today, I noticed an old method for implementing std::enable_shared_from_this by keeping a std::weak_ptr to self in the constructor. Somthing like this:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
// use m_weak.lock() to access the object
//...
private:
X() {}
std::weak_ptr<X> m_weak;
};
But then something came to me regarding constness of this object. Check the following code:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void indirectUpdate() const {
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
private:
X() {}
std::weak_ptr<X> m_weak;
int val = 0;
};
int main() {
auto x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
In this code, indirectUpdate() is a const method and it should not update our object, but in fact it does. Because std::weak_ptr.lock() returns a non-const shared_ptr<> even though the method is const. So you will be able to update your object indirectly in a const method. This will not happen in case of std::enable_shared_from_this because shared_from_this returns a shared pointer to const ref of object in const method. I wonder if this code is UB or not. I feel it should be, but I'm not sure. Any idea?
Update:
Sorry, it seems that my question was not relayed correctly. I meant even if we have a const pointer, we lose that constness via this method. following code shows that:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void show() const { std::cout << "const \n";}
void show() { std::cout << "non-const\n";}
void indirectUpdate() const {
show();
m_weak.lock()->show();
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
int val = 0;
private:
X() {}
std::weak_ptr<X> m_weak;
};
int main() {
// Here we have a const pointer
std::shared_ptr<const X> x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
and output will be following:
0
const
non-const
1
which shows losing constness.
The object that is modified is not const. There is no undefined behavior.
Add a method like this:
#include <memory>
#include <iostream>
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void show() const { std::cout << "const \n";}
void show() { std::cout << "non-const\n";}
void indirectUpdate() const {
m_weak.lock()->show();
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
private:
X() {}
std::weak_ptr<X> m_weak;
int val = 0;
};
int main() {
auto x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
To get this output:
0
non-const
1
Modifying an object via a const mehtod is ok, as long as the method only modifies an object that is actually not const.
It is similar to using a const & to a non-const object. You may cast away constness and modify it as long as the object is really not const:
#include <iostream>
int main() {
int x = 0;
const int& ref = x;
const_cast<int&>(ref) = 42;
std::cout << x;
}
I also see no danger of misusing the pattern in your code, because once the object is const you won't be able to assign to its val member and all is fine with constcorrectness.
In your Update you have a const pointer in main but the object is still not const. Consider this simpler example:
#include <iostream>
struct foo {
static foo* create(){
auto x = new foo();
x->self = x;
return x;
}
void bar() const {
this->self->non_const();
}
void non_const() {
std::cout << "Hello World\n";
}
foo* self;
};
int main() {
const foo* f = foo::create();
f->bar();
delete f;
}
Its not quite the same as yours, but it has similar effect of calling a non-const method on a seemingly const object. Though its all fine.
The only foo object is that created in foo::create, it is not constant. In main we have a const foo* to that object. main can only call the const member bar. Inside bar the this pointer is a const foo*, but self does not point to a const foo. self itself is `const, but not the object it points to.
Hi I am trying to have a getter in my class that returns a "read-only" reference to a vector of objects. Each of those objects its own variables and functions, that I need to call. The way that I am trying to set this up is to have the getter in the main class return a const reference. However, I don't seem to be able to access the values of the objects held in the vector. Is there a better way to do this? Here is a smallest reproducible example. Thank you.
#include <vector>
class Obj
{
private:
int val;
public:
Obj() { val = 10; }
inline int getVal() { return val; }
};
class Foo
{
private:
std::vector<Obj> obsVec;
public:
Foo()
{
Obj a;
Obj b;
obsVec.push_back(a);
obsVec.push_back(b);
}
const std::vector<Obj>& getConstRef() const { return obsVec; }
};
int main()
{
Foo foo;
foo.getConstRef()[0].getVal(); // Here is where I get the error
return 0;
}
The error that I get is:
Error (active) E1086 the object has type qualifiers that are not compatible with the member function "Obj::getVal"
You need to declare getVal() as const:
inline int getVal() const { return val; }
instead of:
inline int getVal() { return val; }
foo.getConstRef()[0] returns const A &, but getVal is not marked const.
Also note that inline is useless here, since functions defined (rather than declared) in class body are implicitly inline.
I would like the compiler to enforce const-ness of an lvalue (non-reference) but don't know if this is possible in C++. An example:
int foo() { return 5; }
int main() {
// Is there anything I can add to the declaration of foo()
// that would make the following cause a compile-error?
int a = foo();
// Whereas this compiles fine.
const int a = foo();
}
This is not really possible with something like an int because you need to give access to read the int and if they can read the int then they can copy it into a non-const int.
But from your comments it sounds like what you have in reality is not an int but a more complex user defined type, some sort of container perhaps. You can easily create an immutable container. This container could be a wrapper, or alternative implementation of your existing container. It then doesn't matter if the caller uses a const or non-const variable it is still immutable.
class MyClass {
std::vector<int> data;
public:
MyClass(size_t size) : data(size) {}
int& operator[](size_t index) { return data[index]; }
int operator[](size_t index) const { return data[index]; }
size_t size() const { return data.size(); }
};
class MyClassImmutable {
MyClass mc;
public:
MyClassImmutable(MyClass&& mc) : mc(std::move(mc)){}
int operator[](size_t index) const { return mc[index]; }
size_t size() const { return mc.size(); }
const MyClass& get() const { return mc; }
};
MyClassImmutable foo() {
MyClass mc(100);
mc[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
MyClassImmutable mci = foo();
std::cout << mci[10] << "\n"; // Can read individual values
//mci[10] = 4; // Error immutable
func(mc.get()); // call function taking a const MyClass&
}
Live demo.
Of course there is nothing to stop the caller from copying each and every value from your immutable container and inserting them into a mutable container.
Edit: An alternative approach might be to return a smart pointer-to-const. The only downside is you have to pay for a dynamic memory allocation:
std::unique_ptr<const MyClass> foo() {
auto mc = std::make_unique<MyClass>(100);
(*mc)[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
auto mc = foo();
std::cout << (*mc)[10] << "\n"; // Can read individual values
//(*mc)[10] = 4; // Error const
func(*mc); // can pass to a function taking a const MyClass&
}
It's not possible. foo() has no way of knowing about the type of the left hand side of the assignment, because when the assignment itself happens, foo() is already evaluated. The best you could hope for is to change the return value, to try and cause a type-based error on the initialization:
#include <type_traits>
struct my_int {
const int m;
template<typename T, typename std::enable_if<std::is_const<T>::value, T>::type* = nullptr>
constexpr operator T() const {return m;}
};
constexpr my_int foo() { return {5};}
int main() {
const int a = foo();
int b = foo();
}
Live example
But this will also not work, because the typename in the template will never be substitued by a const-qualified type (in this specific case, it will be int for both lines in main()).
As the following is possible
const int x = 4;
int y = x;
the C++ language will not provide such a mechanism.
Remains making a int const by a macro mechanism.
#define int_const_foo(var) const int var = ___foo()
int_const_foo(a);
Drawback: foo cannot be hidden, and the syntax is no longer C style.
Is there a way in C++03 (or earlier) to write a class that can either store a const or non-const pointer, and handles access appropriately? Take the usage of the non-functional "SometimesConst" class as an example:
class SometimesConst
{
public:
SometimesConst(int * buffer) : buffer(buffer) {} // Needs const qualifier?
int* get() { return buffer; } // Needs const qualifier?
void increment() { counter++; }
private:
int * buffer; // Needs const qualifier?
int counter;
};
void function(int * n, const int * c)
{
// These are both okay
SometimesConst wn(n);
SometimesConst wc(c);
// Reading the value is always allowed
printf("%d %d", wn.get()[0], wc.get()[0]);
// Can increment either object's counter
wn.increment();
wc.increment();
// Can set non-const pointer
wn.get()[0] = 5;
// Should generate a compiler error
wc.get()[0] = 5;
}
Creating a const SometimesConst would not allow modification of the counter property of the object. Can a class be designed that has compile-time const safety for input objects, only if they are passed in as const?
No, not the way you are wanting to use it. The only way to have different behavior at compile time is to have different types. However, you can make that fairly easy to use:
#include <stdio.h>
template <typename T>
class SometimesConst
{
public:
SometimesConst(T* buffer) : buffer(buffer) { }
T* get() { return buffer; }
void increment() { ++counter; }
private:
T *buffer;
int counter;
};
typedef SometimesConst<const int> IsConst;
typedef SometimesConst<int> IsNotConst;
void function(int * n, const int * c)
{
IsNotConst wn(n);
IsConst wc(c);
// Reading the value is always allowed
printf("%d %d", wn.get()[0], wc.get()[0]);
// Can increment either object's counter
wn.increment();
wc.increment();
// Can set non-const pointer
wn.get()[0] = 5;
// Should generate a compiler error
wc.get()[0] = 5;
}
The language already mostly lets you do this with a simple class; with the way const cascades to access to members (combined with mutable for the counter member, which you've indicated should always be mutable), you can provide both read-only and read-write access to a buffer quite easily:
class C
{
public:
C(int* buffer) : buffer(buffer) {}
const int* get() const { return buffer; }
int* get() { return buffer; }
void increment() const { counter++; }
private:
int* buffer;
mutable int counter;
};
void function(int* n)
{
// These are both okay
C wn(n);
const C wc(n);
// Reading the value is always allowed
printf("%d %d", wn.get()[0], wc.get()[0]);
// Can increment either object's counter
wn.increment();
wc.increment();
// Can set non-const pointer
wn.get()[0] = 5;
// Generates a compiler error
wc.get()[0] = 5;
}
What you can't do with this is neatly arrange for the class to be instantiated with either a int* or a const int*; the two lead to totally different semantics for your class, so you should split it into two if you really need that.
Fortunately, templates make this easy:
template <typename T>
class C
{
public:
C(T* buffer) : buffer(buffer) {}
const T* get() const { return buffer; }
T* get() { return buffer; }
void increment() const { counter++; }
private:
T* buffer;
mutable int counter;
};
Now a C<int> is as above, but a C<const int> only provides read-only access to the buffer, even when the C<const int> object itself is not marked as const:
void function(int* n1, const int* n2)
{
C<int> a(n1);
C<const int> b(n2);
const C<int> c(n1);
const C<const int> d(n2);
// Reading the value is always allowed
printf("%d %d %d %d",
a.get()[0], b.get()[0],
c.get()[0], d.get()[0]
);
// Incrementing the counter is always allowed
a.increment();
b.increment();
c.increment();
d.increment();
// Can set non-const pointer
a.get()[0] = 5;
// Cannot set const pointer, or const/non-const pointer behind const object
//b.get()[0] = 5;
//c.get()[0] = 5;
//d.get()[0] = 5;
}
Live demo
I think that there is a design problem if you want to store two different things which must be handled in different ways in one class. But yes, you can do it:
struct X{};
class A
{
public:
A(const X*) { cout << "const" << endl; }
A(X*) { cout << "non const" << endl; }
};
int main()
{
const X x1;
X x2;
A a1(&x1);
A a2(&x2);
}
the output is expected:
const
non const
I want to implement the class with the following properties:
class A { ... };
const A a; // ok - should work.
A b; // compilation error - shouldn't work!
Also, it would be better, if the constness of an object depends on the constructors signature:
const A c(1); // ok - should work.
A d("a"); // ok - should work.
A e(2); // compilation error - shouldn't work!
Usage of C++11 is allowed, if required.
Update #1
Since I don't know the answer, it's not required to strictly follow the code above - any C++ pattern providing similar semantics is welcome.
1.You can create class with only const methods and private members.
2.You can create "normal" class but declare its constructor as private. Then you will need a friend-class with following method (or something similar)
class ConstClassProvider{
public:
static const A* getA(/* you can have params here*/)
{
return new A();
}
}
so
A a1;//error
const A a2;//error
A *a3 = ConstClassProvider::getA(); //error
const A *a4 = ConstClassProvider::getA(); //ok!
You need to make an immutable class. In other words use encapsulation to prevent users of your class from setting any fields.
Basically:
class Immutable{
private:
const int intField;
const std::string textField;
public:
Immutable(const std::string& ref, int copy) : intField{copy}, testField{ref} {}
int getIntField(){return intField;}
const std::string& getTextField(){ return textField; }
}
Then just don't expose your internals via setters.
You can do that with an extra constructor argument which is a reference to self, e.g.:
class X {
public:
X(X const& self) {
assert(this == &self);
}
private:
X(X&);
};
And then invoke it like so:
X const x(x); // works
X y(y); // fails to compile
X z(x); // fails at run-time
Probably this is you are looking for:
class AData {
public:
AData() : intValue( 0 ), stringValue( 0 ) {}
void SetInt( int arg ) { intValue = arg; }
void SetString( const char* arg ) { stringValue = arg; }
private:
int intValue;
const char* stringValue;
};
class A {
public:
A();
void Init( int intValue ) const;
void Init( const char* stringValue );
private:
AData* p;
};
A::A() : p( new AData )
{
}
void A::Init( int intValue ) const
{
p->SetInt( intValue );
}
void A::Init( const char* stringValue )
{
p->SetString( stringValue );
}