I just started learning C++, switching from a JAVA environment.
When reading through some Boost examples I found the following two methods defined in a class:
const char* data() const
{
return data_;
}
char* data()
{
return data_;
}
There are two things that confuse me.
First is the reserved word const, which I think I understand here. The first const refers to the char* which means that I cannot change the value of the pointer. The second const tells me that calling the function will not make changes to the state of the object I am calling. Is that a correct interpretation?
Second point of confusion is why one would have two methods with the same name and signature. How does the compiler know which one I meant to call? How do I know whether I am allowed to change the data after calling data() without know which of the two I called?
The first function returns a pointer to constant data. The const at the end of the function signature indicates that the function will not modify and class data members.
The second function returns a pointer to mutable data. The caller can use the pointer to modify the class member variable.
Search the web and SO for "const correctness".
There are several ways to declare const within a variable with a pointer:
const char * // you can modify the pointer, not the item pointed to
char const * // you can modify the pointer, not the item pointed to
char * const // you can modify the item pointed to, not the pointer
const char const * // you cannot modify either
char const * const // you cannot modify either
const char * const // you cannot modify either
As for the question, these two method definitions are overloads, and which one is called depends on the context. For example, if the caller is also in a const method, and making the call on one of it's members (who is an instantiation of the class that has the data() methods), then the const char * data() const method will be called, and caller can only save the return value in a variable of type const char *. Here is an example:
class MyClass {
DataClass data_obj_; // has both 'data()' methods described in your question
...
void my_method () const { // within this const method, data_obj_ cannot be modified
const char * data = data_obj_.data(); // calls const method
...
Here is an example where you would need both.
class foo {
char* data_;
public:
const char* data() const
{
return data_;
}
char* data()
{
return data_;
}
};
const foo bar;
foo bar2;
bar->data(); // this uses the const version.
bar2->data(); // this uses the non-const version.
Because bar is a const object it would be an error to call data() non-const version.
Related
I have this class:
class BankAccount{
private:
char* ownerName;
char IBAN[14];
double balance;
}
And I have this function:
char* BankAccount::getIban(){
return this->IBAN;
}
That one is valid but I wonder why I can't define getIban() like this, because I want to make sure that IBAN can't be changed :
char* BankAccount::getIban()const{
return this->IBAN;
}
It says return value does not match the function type.
Inside a const function all of the members behave as if they were const, in your case the member IBAN is equivalent to const char IBAN[14]. You cannot get a non-const char* to refer to a const array, and thus the error. You probably want to do:
const char* BankAccount::getIban() const {
return IBAN;
}
you have to include const in the function declaration in the header
If you declare a method const when defining it the compiler WONT LET YOU potentially ruin that const-ness by passing pointers to const stuff outside where they're not const.
The error is that. You need to return a const char*, that way the compiler knows when you use that function the resulting type is a const char* <-- you can look but not touch, so the IBAN value stays const.
If you make the const method return a const char* (return IBAN) it'll be fine, because when you use that method C++ wont let you change what the result of calling it points to.
class A has an object that can be shared, but only internally modified
class A
{
public:
validityClass ** getValidityShared() // I want to make this const return, not sure how to protect a double pointer const signeture
{
return &validityShared;
}
private:
validityClass * validityShared;
}
class B need an access, read for validations, or B class population through its constructor
class B
{
B(A & ainst)
{
aValidityShared = ainst.getValidityShared();
}
private:
validityClass ** aValidityShared;/// tried to save it as validityClass ** & aValidityShared but I guess its wrong, even though everything worked out
}
after B constructor is over, I am no longer need to know anything about A class!
int main(int argc, char* argv[])
{
A instA;
B(&instA);
return EXIT_SUCCESS;
}
I want B intance to have the A shared variable, but without any extra resources, so I tried to save it as an rValue.
what do you recommend? (save internally as an rvalue or const
(double const))
how is the const protection for a double pointer?
or just never keep it internally saved?
by the way the example is slightly different than what I am using, but it is the same context
and I am asking this question because I am getting some weird warning:
member initializers forconst char ** classB::xVar`
validityClass ** getValidityShared()
// I want to make this const return, not sure how
// to protect a double pointer const signeture
You need to add const to the value and the pointers, so to provide real const-correctness that signature would be:
validityClass const * const * getValidityShared() const
The second pointer need not be const, as that is a value. I placed the const on the right, as that is the right thing to do, and I believe it makes it more readable.
You could also return a reference, in which case you would want:
validityClass const * const & getValidityShared() const
I have a class Foo which is in a self referencing tree-like structure (minimally):
class Foo {
public:
// Gets this child's position relative to it's parent.
int getPosition() const {
return parent->indexOf(this);
}
int indexOf(const Foo *const child) const {
return children.indexOf(child); // this line causes an error.
}
private:
Foo *parent;
QList<Foo *> children;
}
The line return children.indexOf(child) expects const T &value to be passed as per the QList docs, this resolves to Foo *const &value for my scenario.
In order for my getPosition() method to call my own indexOf() method it is required to have a signature of const Foo *child at minimum in order to pass this from a const method. (Since this is const Foo *const).
My code will not compile however as const Foo *const child cannot be cast to Foo *const child for QList::indexOf. Neither of my methods modify the object state so they should be const (i.e. I don't want to un-cost getPosition to receive a non-const this).
So the question is, how do I go from this in a const context (const Foo *const) to what QList::indexOf requires. Should I be const casting this inside getPosition since I know that my indexOf (and subsequent calls) will not mutate it?
Is there something else I should have done? Perhaps my design is faulty.
I think this is a perfectly reasonable use case for const_cast, however it's not this you need to const_cast, but child. In this case, QList::indexOf expects a constant pointer to a Foo (Foo* const) but child is a constant pointer to a constant Foo (const Foo* const). There is no implicit conversion from Foo* const to const Foo* const because that would remove the const-ness from the value being pointed to.
So, to fix your code I would change the line to
return children.indexOf(const_cast<Foo*>(child));
You know QList::indexOf is not going to modify whatever child points to, so this won't produce undefined behavior. I would however add a comment explaining why the const_cast is necessary.
Code goes first:
class A
{
public:
...
int *foo() const
{
return _px;
}
private:
int *_px;
}
The member function foo returns a non-const pointer to private member _px, which, I think, opens a door to modifying member _px, right?
Is foo a const member function? Should I add a const in front of the return type?
UPDATE
What a const-member-function should guarantee is that, it cannot change any data-member, right?
In my case, function foo doesn't open a door to modifying class As data-member _px, but a door to modifying what _px pointing to, So my question is, does this violate what a const-function should guarantee?
A const member function can only return a const pointer or reference to a member.
However, your example isn't returning a pointer to a member; it's returning a copy of a member that happens to be a pointer. That is allowed in a const member function (even if the pointer happens to point to another member).
This would not be allowed (note that it's now returning a reference):
int *& foo() const {return _px;}
but this would (returning a const reference):
int * const & foo() const {return _px;}
int *_px becomes int *const _px inside a const member function this implies that the pointer cannot be reseated but the data pointed to is still modifyable. Further your function returns a copy of the pointer so it does not matter anyways.
It does not open a door to modifying _px but rather what _px points to. It's up to you to decide whether you want to allow this or not.
For example, an iterator::operator-> would return a non-const pointer and const_iterator::operator-> would return a const pointer. Both methods can be const themselves.
Yes, for your case it can. However, it's generally advised to not to do this, because it allows changing constant objects:
void f(const A& a)
{
*(a.foo()) = 42; // damn!
}
Yes, for example see the std::streambuf pointers:
protected:
char* pbase() const;
char* pptr() const;
char* epptr() const;
http://en.cppreference.com/w/cpp/io/basic_streambuf/pptr
I have a program and many of its classes have some operators and methods with the keyword const like the followings:
operator const char* () const;
operator char* ();
void Save(const char *name) const;
void Load(const char *name);
First: what does it mean const at the end of the method declaration?, is it the same like putting it at the beginning?
Second: Why would be a const version and a no const version of operator() needed?
Thanks in advance.
First: what does it mean const at the end of the method declaration?, is it the same like putting it at the beginning?
No. A const at the end means that the method may be called on objects that are declared const. A const at the beginning means that the returned value is const.
Second: Why would be a const version and a no const version of operator() needed?
The non-const version returns a char* which is not const. By modifying this char* you could then in fact modify the object (assuming the char* is a member of the object).
Since this is not allowed for const objects, there's an overload of operator() for const objects, so that a const char* is returned, so the object can't be modified through it.
'const' at the end tells the compiler that this method does not change any member variables - that it is safe to call this method on const instances. So, Save could be called on a const instance, since it won't change that instance. Load on the other hand, will change the instance so can't be used on const instances.
The const version of operator() passes back a const pointer, guaranteeing the buffer passed back won't change. Presumably that's a pointer into a instance variable of the class. For non-const instances, the other operator() passes back a non-const pointer. It would have to be a pointer to some memory that even if written to, wouldn't change the contents of the instance.
Also, look up the 'mutable' keyword sometime. Understanding that will help you understand this idea of const-correctness.
Member function constness. It means the function can not(*) modify any of your member variables. It's like putting a const in front of all your member variables for this one function call. It's a good guarantee for the clients of your class and may also aid in compiler optimisations.
(*) - see also the keyword mutable.
Putting const at the end of a method declaration is stating that the object itself, or this, is const instead of the return type.
C++ allows methods to be overloaded on const for complicated reasons. Not enough space to go into full detail here. But here are a couple of short ones.
Ocassionally there is value, or flat necessity, in having a method behave differently when it is called from a const type. The most straight forward example is when you want to return a const value from a const method and a non-const value from a normal method.
Whether or not this is const dramatically changes the binding of the internal method. To the point that it would essentially become two different method bodies. Hence it makes sense to break it up into 2 different methods.
One note in addition to the other answers: there is no operator() in your example.
operator const char* () const;
operator char* ();
are conversion operators, which mean that objects of the class can be implicitly converted to C-style strings, like
void f(const MyClass& x, MyClass& y) {
const char* x_str = x;
char* y_str = y;
}
A declaration and usage of operator(), which means you can use an object of the class type sort of like a function, would look like:
class MyClass {
public:
const char* operator() (int x, int y) const;
// ...
};
void g(const MyClass& obj) {
const char* result = obj(3, 4);
}
If you're looking for a great resource on C++ (including tips on using const correctly) try "Effective C++".
A useful site about this: JRiddel.org
In C++ when you declare a method const by putting it AFTER the method signature you are asserting that "This method will not change any non-mutable instance variables in the object it is being called on."
The const before the return value (e.g. the const in: operator const char*...") is declaring that it only returns a variable pointer to a const char*. (You may not change the contents of the char* but you can re-assign the pointer.) If you wrote "const char* const ..." it would be a constant pointer to constant characters. (The const comes after the star).
The multiple versions are useful so the compiler can understand this:
const char* my_const_var = <object_name>();
char* my_var = <object_name>();
Chris
You should refer to the "HIGH·INTEGRITY C++ CODING STANDARD MANUAL" for knowing when it is recommended to use the const modifier for class members:
High Integrity CPP Rule 3.1.8: Declare 'const' any class member function that does not modify the externally visible state of the object. (QACPP 4211, 4214)
Justification: Although the language enforces bitwise const correctness, const correctness should be thought of as logical, not bitwise. A member function should be declared const if it is impossible for a client to determine whether the object has changed as a result of calling that function. The 'mutable' keyword can be used to declare member data which can be modified in const functions, this should only be used where the member data does not affect the externally visible state of the object.
class C
{
public:
const C& foo() { return * this; } // should be declared const
const int& getData() { return m_i; } // should be declared const
int bar() const { return m_mi; } // ok to declare const
private:
int m_i;
mutable int m_mi;
};
Reference Effective C++ Item 21;Industrial Strength C++ 7.13;
Const at the beginning applies to the return value. Const at the end applies to the method itself. When you declare a method as "const" you are saying that you have no intention of modifying any of the member variables of the class in the method. The compiler will even do some basic checks to make sure that the method doesn't modify member variables. The const in the return value prevents the caller from modifying the value that is returned. This can be useful when you return pointers or references to data managed by the class. This is often done to avoid returning copies of complex data which could be expensive at run time.
The reason you have two different operators is that the "const" version returns a const pointer to what is probably data internal to the class. If the instance of the class is const, then chances are you want the data being return should also be const. The "non-const" version just provides a method that returns a modifiable return value when the caller has a non-const instance of the class.