I have const on the Accelerate method, yet I can call the power method. Is their a way to actually stop this.
class Engine{
public:
void Power(){
}
};
class Car{
public:
Car() : p(new Engine()){}
void Accelerator() const{
p->Power();
}
private:
Engine* p;
};
For Car, a const method is a methods which does not modify Car member variables.
so, as long that Car::Accelerator does not make p point to a different location, it is valid.
since p is not modified in Accelerator (meaning it does not point to a different memory address), the program is valid.
the moment you make p point to a different location, the program fails to compile:
void Accelerator() const {
p= nullptr; //wrong
}
Const protection affects only the direct members, in this case the pointer only. Values outside this object (aka. pointed values) are not protected.
You have to decide if you consider the pointed value as yourself or someone else.
You can modify the member Engine as const*, which will make the Engine object pointed to by p in Car const:
class Engine{
public:
void Power(){
}
};
class Car{
public:
Car() : p(new Engine()){}
void Accelerator() const{
p->Power();
}
private:
Engine const* p;
};
This will no longer compile:
test_const.cpp:12:9: error: member function 'Power' not viable: 'this' argument
has type 'const Engine', but function is not marked const
p->Power();
^
test_const.cpp:3:10: note: 'Power' declared here
void Power(){
^
But this implies that no member of Car can modify *p, which is probably not what you intend. See #NathanOliver's comment for better answer.
Hope this helps.
Related
I have a class, it names A and A class has 3 another class in its private.
class A{
public:
A();
A(int num);
A(C& mC, P& mP, M& mM, int num);
//there is a getter and setter for all member this only one example(please check are they right?)
M getM()const{return pM;}
void setM(M classM){ pM = classM ;}
private:
C& pC;
P& pP;
M& pM;
int digit= 0;
};
I'm doing that in parameter constucture:
A::A(C& mC, P& mP, M& mM, int num):pC(mc),pP(mP),pM(mM)
{
// doing someting here
}
But I can't write a code for default and first parameter constructure, when I write something compiler saying to me that :
error: uninitialized reference member in ‘class A&’ [-fpermissive]
A::A(){
and
note: ‘A& A::pP’ should be initialized
A& pP;
someting like this, several errors and notes.
What should I do? How can I initialize classes in default and first parameter constructure?
Class A contains references to other object. Unlike pointers, references cannot be null. To make this work, you either need to:
Use pointers instead of references, and initialize them to nullptr is no valid object is provided in the constructor
Store those members by value. This involves a copy of the original arguments, and different in semantics - might not be what you need.
Suppose we have a following piece of code:
class Base {
public:
int a = 5;
};
class Derived : public Base {
public:
Base *parent_ = new Base;
Base* parent() const { return parent_; }
};
void f(const Derived *derived) {
Base *p = derived->parent();
p->a = 10; // <- is this correct?
}
Personally I think here is a problem:
In function f we take a pointer to const object of class Derived. This makes each member of it also const thus parent_ becomes const Base *. If it is const we should not have an ability to modify the object on which the pointer points.
Where am I wrong?
This makes each member of it also const thus parent_ becomes const Base *.
No, the pointer will become const itself, not the object it points to. So parent_ becomes Base * const, not const Base *, and your code is valid.
Base* parent() const { return parent_; }
Unfortunately, this is problem with C++. Method is const, but it is returning a non-const pointer, which would allow following operation to succeed:
p->a = 10; // <- is this correct?
It is programmer's responsibility not to return non-const pointer or references from functions (method being const or not).
As tobi303 points out below, this answer is wrong. Keeping it here for the sake of the discussion below.
I could be wrong, but this line:
Base* parent() const { return parent_; }
does not mention anything about returning const objects. It is equivalent to
Base* parent() const { return this->parent_; }
where this is const Derived*, but parent_ is still Base*.
A const method only prevents the method from modifying any non-mutable data members of the class.
If you want to not allow the modification of a and don't want to update the class, you need to write:
const Base *p = derived->parent();
However, I would recommend you to not return non-const data members from a class as ref or pointer because this breaks the data encapsulation concept of C++. This is the same, of course, with the public a.
I read a line in Meyers:
"A member function that modifies what a pointer points to frequently doesn`t act const.
But if only the pointer is in the object, the function is bitwise const, and compilers wont complain."
I fail to understand that modifying a pointer in a function cannot maintain its bitwise constantness since its a member variable...
Even if we assume that bitwise constantness is only for values that pointers point to and not for the pointer addresses themselves..
Then why does it matter if its the only member variable in the class or if its not the only only member variable..
Basically this means that if you had
struct Foo
{
int bar;
};
you couldn't have a const member function change the value of bar.
However if bar is a pointer to an int, you could change the value of the int in a const method because the int is not actually part of the struct.
Both versions achieve the same goal (i.e. change the value of the int) but in the first version you are breaking bitwise constness and the compiler will complain, in the second it wont.
It's bitwise const because the member function only
modifies what [the] pointer points to
so the object instace data (the member pointer) doesn't change only the object on the heap that it points to.
Take the following simple classes:
class A
{
public:
A(int d = 0) : data(d) {}
void func() const
{
++data; // Can't do this. That's changing
// the bitwise content of this.
}
private:
int data;
};
And
class B
{
public:
A(int d = 0) : data(new int(d)) {}
void func() const
{
++(*data); // Can do this. That doesn't change
// the bitwise content of this.
}
private:
int* data;
};
If I read it correctly, a member function usually isn't qualified const if it modifies a value pointed at by a pointer stored in the current object:
class A {
char* string;
public:
void UpCaseString() { strupr(string); }
....
}
The UpCaseString() method modifies data which 'belong' to the object, so it usually would not be declared as const. However it actually modifies some buffer allocated outside the current object, the instance of A class has only a char* pointer to the buffer—so the buffer can still be modified even when the object itself is const:
class A {
char* string;
public:
void UpCaseString() const { strupr(string); }
....
}
void foo(A const &a) {
a.UpCaseString();
}
Member a.string is not modified here.
is it possibile do this kind of cast in C++?
I need to declare my attribute in this way.
Class A {
public:
void update() { ++i_; }
private:
int i_;
}
Class B{
public:
void foo() {
a_->update(); /* Error */
}
private:
const A* const a_;
}
Error is:
passing ‘const A’ as ‘this’ argument of ‘void A::update()’ discards
qualifiers [-fpermissive]
I try with static_cast, but is not enough.. does not work.. any ideas?
You have two choices here. Either make A::update a const function-
Class A {
void update() const;
}
or remove the constness of the pointer.
Class B{
public:
void foo() {
const_cast<A*>(a_)->update();
}
private:
const A* const a_;
}
The former would be the preferred method, but that will also stop you from doing anything useful in class A's update.
As a rule of thumb, if you have to cast the const off something then you really want to look at why the pointer is const in the first place.
Using a const member with a non-const method is forbiden (unless using mutable). Put a const after declaration of foo() and update():
void update() const { ... }
^^^^^
void foo() const { ... }
^^^^^
or ...
If you don't want to make update a const, you can use const_cast:
void foo() const // Now, this const keyword is optional but recommanded
{
const_cast<A*>(a_)->update();
^^^^^^^^^^^^^^
}
You've got a few options:
use const_cast to cast away the const and call the method.
make update a const method, so that it can be called through a const pointer.
don't store a_ as const in the first place. Change it to A* const a_ so that you can call non-const methods, but the pointer cannot be changed.
Assuming that you cannot declare the method as const and that you know what you are doing (tm) and why this is bad: Try the const_cast!
The const after * has nothing to do with it. You must declare your functions which use a_ as const functions. If they don't compile, you must use const_cast or reinterpret_cast to remove const from the pointer before calling.. But this is very dodgy, and if update() function modifies an object which was originally declared const, this is undefined behaviour.
The error you get
passing ‘const A’ as ‘this’ argument of ‘void A::update()’ discards
qualifiers [-fpermissive]
is result of calling non-const method on a const pointer. This is forbidden. Since you require an update to be non-const and you cannot store a pointer to non_const A, you can use operator const_cast to cast away const and here is how to do it:
class A {
public:
void update(){}
};
class B{
public:
void foo() {
const_cast< A*>(a_)->update(); /* OK*/
}
private:
const A* const a_;
};
You should however rethink your design.
As mentioned by someone before, use mutable/const but this changes your design a little bit:
class A {
public:
void update() const { ++i_; } // this will make the method callable by const A*
private:
mutable int i_; // and this will make you field mutable in a const method
};
class B{
public:
void foo() {
a_->update();
}
private:
const A* const a_;
};
I'd like to declare a primitive type member in a class that forbids usage of operator&(). In other words: I don't want anyone to ever take the address of this member (and possibly pass it to other classes or functions, etc.)
Is this possible without using a wrapper type?
You can declare operator&() as private which prevent the address being taken with the & prefix, but std::addressof can always be used to circumvent that. Taking the address cannot be prevented, but it can be made for difficult as a deterrent.
Assume your class is A
Put this in your class declaration
A* operator&() = delete;
Declare your member as private, and your getter doesn't return reference/pointer.
it works also for non primitive-class (with the cost of the copy)
class A
{
public:
const A* operator & () const = delete; // pre-require of OP
A* operator&() = delete; // pre-require of OP.
int getMember() const { return member; }
void setMember(int value) { member = value;}
// Other stuff.
private:
int member;
};