This is a follow up of the Previous Question
It got really complicated so I am starting a new thread to make my point clearer.( Didnt want to delete the previous thread because the other guys who gave valuable feedback dont not loose the reputation points they gained)
Updated Code: (Complies and Works)
#include <iostream>
using std::cout;
class Test {
public:
Test(){ }
int foo (const int) const;
int foo (int );
};
int main ()
{
Test obj;
int variable=0;
int output;
do{
output=obj.foo(3); // Call the const function
cout<<"output::"<<output<<std::endl;
output=obj.foo(variable); // Want to make it call the non const function
cout<<"output::"<<output<<std::endl;
variable++;
usleep (2000000);
}while(1);
}
int Test::foo(int a)
{
cout<<"NON CONST"<<std::endl;
a++;
return a;
}
int Test::foo (const int a) const
{
cout<<"CONST"<<std::endl;
return a;
}
Output (I get):
NON CONST
output::4
NON CONST
output::1
NON CONST
output::4
NON CONST
output::2
NON CONST
output::4
NON CONST
output::3
NON CONST
output::4
NON CONST
output::4
NON CONST
output::4
NON CONST
output::5
Output (I desired/had in mind)
CONST
output::3
NON CONST
output::1
CONST
output::3
NON CONST
output::2
CONST
output::3
NON CONST
output::3
CONST
output::3
NON CONST
output::4
CONST
output::3
NON CONST
output::5
Hope I have presented my question better. I know other ways to do it. but is this possible.
In C++, the function signatures
int Test::foo (const int a) const
and
int Test::foo (int a) const
are considered to be complete identical.
The reason that the const on the parameter is disregarded is because it can not affect the caller in any way. As the parameter is passed by value, a copy is made of the value provided by the caller. To the caller, it does not matter in any way if the called function can change that copy or not.
For this reason, C++ ignores a top-level const-qualification on function parameters (top-level const can not occur if passing a reference), and goes even as far that int foo(int); is considered a correct prototype for the function
int foo(const int)
{
/* ... */
}
In short, it is impossible in C++ to overload a function on the constness of (value) function parameters.
To get the output you want, you could consider using a non-const reference parameter for your non-const overload.
The call of const (or non-const) function doesn't depend of the constness of the parameters but only of the constness of the called object (in our case obj). Overload needs different type and (non-const const) are not, so I don't think you can overload as you are doing it. (that work because you are defining a const and a non-const methods but that's not overloading.)
To persuade yourself, try to remove the const at the end of your declaration to see if you are allowed to declare
int foo(int a);
int foo(const int a);
You'll get an error.
In the second case you think foo is expecting a const int as argument but not. const is tied to a not to int. So what it says is foo expect an int, you could refer it using a and that will be const : you are not allowed to modify a. That's why the const (of a parameter) doesn't appear in the function signature (that would be different for a reference).
The const outside the function refers to object called , so that's part of the signature
int foo(int a); # type => int (Test::*)(int)
int foo(const int a) const; # => int (const Test::*)(int)
int foo(const int a) ; # => int (Test::*)(int)
int foo(int a) const; # => int (const Test::*)(int)
(I'm not 100% sure about the type syntax , so don't comment on it, that's just to give an idea)
As you can see the const get removed with a. You can also write it int const a, even if not the standard way to do it, it's perfectly legal.
By the way , your code will never do what you are expected, you should use a reference to an int to modify it
int Test::foo(int &a) ...
Okay, this is how it works:
When you call a function, the value of the parameters are passed to the function. If you pass a value, then this value will be what the function gets. If you pass a pointer, then your function will get a pointer.
When your function receives the argument, all it sees is an integer value. It cannot determine where this value came from, and cannot be static or non static. These properties belong to pointers, which indicate whether or not you can change the value pointed to by the pointers, not the pointers themselves.
Just for good measure, all these function calls look IDENTICAL to the function that recieves them:
int i=1;
int* b = new int;
*b = 4;
func(5);
func(3+2);
func(i+4);
func(*b+1);
So to answer your question, what you are doing is not possible.
EDIT: To change the variable, overload the function with an int, and an int pointer. By passing the address of an int value to the function, your function can change it.
Yep, I can't make it call the const version - unless I do this:
const Test obj2;
output=obj2.foo(3); // Call the const function
No matter what parameter is passed in, if it can call the non-const, it will. If you have a const object, it calls the const version of the function.
Interesting.
Just a clarification. However, we are allowed to overload pointers with and without const arguments in functions, right?
As in,
int Test::foo (const int* a);
int Test::foo (int* a);
How is this different?
Convert you const int to a string, overload your foo with a string and convert back...
Feel free to destroy my answer and the comments.
Related
This has probably been already asked.
Why is it allowed to assign a reference-to-const to a non-const variable?
Why is this allowed
int mut {0};
const int & r_to_c {mut};
mut = 1;
// now r_to_c changed to 1!
// But it was supposed to be a reference to something constant!
?
Sure, I cannot mutate the value from the reference-to-const itself. I cannot
r_to_c = 2;
but isn't the const qualification enforcing too little? I would expect, from a promise of const-ness, that binding to mutable variables was disallowed.
Otherwise what guarantees is const giving me? They seem pretty weak, and it seems that this could easily trick programmers to shoot themselves in their foot.
I know that C++ has a reputation for allowing people to shoot themselves in their foot. I don't have a problem with allowing dangerous things. In this case, my problem is that in this case it seems that it is purposefully deceiving, given that the semantics of const here is not the one would expect it.
Mine is a question about the compiler and the language semantics, not about references in particular (I could have asked the same question using a pointer-to-const that is assigned to the address of a non-const variable. Like int mut{0}; const int * p_to_c{&mut};).
Why is the semantics of a reference-to-const (or pointer-to-const) just "you can't use this particular window to modify the thing you see (but if you have other windows that are non-const, you can modify it)" instead of a more powerful "this can only be a window to something that was declared constant and that the compiler guarantees it stays constant"?
[Note on terminology: I use the expression "reference-to-const" instead of "const reference" because a "const reference", interpreted as T& const - consistently with calling T* const a "const pointer" -, does not exist.]
but isn't the const qualification enforcing too little? I would expect, from a promise of const-ness, that binding to mutable variables was disallowed.
No it is not "too little". You are expecting the wrong thing.
First, whether you bind a const reference does not make the object itself const. That would be strange:
void foo(int& x) {
static const int& y = x;
}
When I call foo:
int x = 42;
foo(x);
I cannot know whether somebody else will keep a const reference to my non-const x.
Otherwise what guarantees is const giving me?
You cannot modify something via a const reference:
void bar(const int& x);
int x = 0;
bar(x);
When I call a function that takes a const& then I know that it will not modify my (non-const) parameter. If const references would not bind to non-const objects then there would be no way to make this last example work, i.e. you could pass non-const objects only to functions that do modify them, but not to functions that do not modify them.
P.S. I can understand your confusion. It is sometimes overlooked that holding a constant reference does not imply that the object cannot be modified. Consider this example:
#include <cstddef>
#include <iostream>
struct foo {
const int& x;
};
int main() {
int y = 0;
foo f{x};
std::cout << f.x; // prints 0
y = 42;
std::cout << f.x; // prints 42
}
Printing the value of the member to the screen yields two different results, even though foo::x is a constant reference! It is a "constant reference" not a "reference to a constant". What const actually means here: You cannot modify y through f.x.
The ability to bind a const-reference to a mutable variable is actually a very valuable feature to have in the language. Consider that we might want to have a mutable variable.
int mut {0};
// ... some time later
mut = 1;
This is perfectly reasonable; it's a variable that is going to change during the execution of the program.
Now let's say we want to print the value of this variable, and would like to write a function to do that.
void print(int param) // or 'int &' to avoid a copy,
// but the point here is that it's non-const
{
std::cout << param;
}
This is fine, but clearly the function is not changing the parameter. We would like that to be enforced so that mistakes like param = 42; are caught by the compiler. To do that, we would make param a const & parameter.
void print(int const & param);
It would be quite unfortunate if we couldn't call this function with arguments that are non-const. After all, we don't care that the parameter might be modified outside the function. We just want to say that the parameter is guaranteed not to be modified by print, and binding a const & to a mutable variable serves exactly that purpose.
A reference to a const object is not the same as a const reference to a non const object, but C++'s type system does not distinguish them.
This is sort of a violation of the LSP; it has the same kind of problem as a reference to a mutable square and rectangle do.
You can create "true const" but you need help at declaration.
template<class T>
struct true_const {
const T value;
};
a true_const<int>& or true_const<T> const& can be passed around as a reference, and nobody can edit it (without invoking UB) "behind your back".
Of course, a function taking a true const cannot also take a normal object.
void bob( true_const<int>& x ) {
auto local = x.value;
call_some_other_function();
assert(local == x.value); // guaranteed to be true
}
void bob( const int& x ) {
auto local = x;
call_some_other_function();
assert(local == x); // NOT guaranteed to be true
}
const fields in classes are truly const; modifying them is undefined behavior.
A thin wrapper around a type that is const within the class is thus a guarantee the data is const. Then take a reference to that.
Now, the true_const could use some operator support.
template<class T>
struct true_const {
const T value;
constexpr T const& get() const { return value; }
constexpr T const& operator*() const { return get(); }
constexpr T const* operator->() const { return std::addressof(value); }
constexpr operator T const&() const { return get(); }
// concepts-defended operator+,==, etc
};
I am writing a code in C++ right now, and I have a dilemma.
EDIT: I added the class relevant definition
_fullName is defined in the class as a private dm(char _fullName)
my class contains the getter method below:
char* getFullName() const { return this->_fullName; }
However, I had in the past cases in which I returned char* with const(const char*)
I can change the getter method to this one:
const char* getFullName() const { return this->_fullName; }
Both versions are compiling but I don't know how to choose.
I would take the second version, but I wonder Why even the version without the const is compiling? shouldn't it give an error when I remove the const keyword, because the function is a CONST member function and therefore the dms are const as well and cannot be returned without the const keyword???
This is the class relevant definition:
class Professional
{
private:
char* _ID;
char* _fullName;
int _age;
char* _profession;
}
First understand what const attached to a member function means. It determines the const-ness of the implicit this used for the member. Given this:
struct S
{
char value[10];
const char *mfn() const { return value; }
};
within the confines of mfn the implicit this is const S *. Furthermore, all references to members obtained therein are also const. In this case, that means value as an expression representation is const char (&)[10] before any further conversion are attached therein.
That's important.
In the correct posted example above there is an automatic conversion to temporary pointer, since const char(&)[10] converts to const char* without objection. However, the following will fail:
struct S
{
char value[10];
char *mfn() const { return value; }
};
The reason this will fail is simply because there is no conversion possible. value, remember, is const char (&)[10], and can only implicitly convert to const char*.
But how could it succeed? Well, consider this:
struct S
{
char *ptr;
char *mfn() const { return ptr; }
};
This will work. The reason is subtle, but obvious once you think about it. ptr is a char*. The attachment of const to this makes that char * const&, not const char *& (there is a difference; the former is a reference to a non-mutable pointer to mutable data, the latter is a reference to a mutable pointer to non-mutable data). Since return ptr is not mutating ptr (or anything else in the object), it is viable as a result.
In short, in your case it works because the pointer you are returning isn't via some implicit conversion from a const underlayment; it's just a value.
You have a few things going on here, in your example of the int num member this is not the same as a char * member.
lets expand your example a bit:
class Professional
{
int* func() const
{
return &myInt; // Fails because it returns a reference to a member variable
}
char* func() const
{
return &myChar; // Fails because it returns a reference to a member variable
}
int* func() const
{
return pInt; // ok because it returns a COPY of the member pointer
}
char* func() const
{
return pChar; // ok because it returns a COPY of the member pointer
}
int myInt;
char myChar;
int *pInt;
char *pChar;
Note: the two pointers getting returned by copy are ok. Its the pointers that are copies not the thing being pointed to. The memory that is pointed to is nothing to do with this class.
As to an answer to your question: there is a rule of thumb that is to apply const as much as possible - this helps to show other users your intent and gains benefits from compiler warnings / errors if a user tries to use your class in a way you did not intend. So in this case pass back a const char *.
Note: See this answer for more specific details here: What is the difference between const int*, const int * const, and int const *?
So Wikipedia tells me (correctly i believe) that to stop the editing of the data of a pointer and the pointer itself that I should do this:
void function(int const * const var)
Is this the same as this function:
void function(const int * const var)
And in that case why is it allowed? Because I know that you cant do this because of duplicate const compile error:
void function(const int const * const var)
I essentially want to do the same with a boost pointer. Would I do this:
void function(const boost::shared_ptr<int> const var)
And how would this affect my ability to loop over say a shared pointer to a vector? Could I do this with that guard:
void function(const boost::shared_ptr<std::vector<int>> const var)
{
for (unsigned int i = 0; i < var->size(); ++i)
{
std::cout << var[i];
}
}
Adition: After Brian's answer
So if I create a a pointer like this:
boost::shared_ptr<vector<int>> lala
And i use it in this function:
function (const boost::shared_ptr<std::vector<const int>> var)
will that work?
Yes, int const * const var is the same as const int * const var. You can put const before or after the type it modifies, for "historical reasons". See http://www.stroustrup.com/bs_faq2.html#constplacement
For a smart pointer object, you indeed cannot do
const boost::shared_ptr<int> const
because both consts modify the same type. Instead, you want
const boost::shared_ptr<const int>
The first const prevents the pointer itself from being modified (i.e., reassigned to point to another int) and the const in the template parameter tells the object's operator* to return a const int&, which prevents modification of the int pointed to.
This does not prevent iteration over a vector or other container in the manner you have described, for the same reason why you can still iterate over a const vector normally.
Edit in response to question edit:
This works:
void f(const boost::shared_ptr<const std::vector<int> > var);
// ...
boost::shared_ptr<vector<int> > lala;
f(lala);
The first const in the parameter doesn't affect parameter passing at all; it only tells the function itself not to modify the parameter. The reason why we can add a const in the template parameter is that a boost::shared_ptr<T> can be initialized from boost:shared_ptr<U> where T and U are not necessarily the same type, as long as U* is implicitly convertible to T*. If T is the same as U except with greater cv-qualification, as in this case, the conversion is possible.
Don't do std::vector<const int>. I'm fairly sure that's not legal. (At least I've gotten multiple screens of compilation errors every time I've tried it.)
const before or after the int is the same so:
int const * var
and
const int * var
are the same and mean the value pointed to cannot be changed
const after the * means that the pointer cannot be reassigned.
If I understand correctly, you'd like to make the vector const. If that's the case the syntax would be this:
void function(const boost::shared_ptr<const std::vector<int>>& var)
The smart pointer is passed by const reference because it's cheaper than passing the smart pointer by value and has the same effect. The object pointed to by the smart pointer is immutable by declaring the type it points to as const.
You've correctly reasoned that const shared_ptr<Foo> doesn't make Foo a const object. This "loophole" is described on wikipedia. Instead, you need to change the pointer type stored by boost::shared_ptr. This can be done in the template argument itself:
void function(const boost::shared_ptr<const std::vector<int>>& var)
boost::shared_ptr has a copy-constructor that allows for a const-type to be copied from a non-const-type. The opposite should not be possible.
Before, or after?
The below two lines are semantically equivalent, both declare a pointer which value cannot be changed, that refers to an int that cannot be changed.
int const * const p1 = ...;
const int * const p2 = ...;
The const keyword binds to whatever is directly to the left, unless there's nothing to the left, in which case it will hug whatever is on the right.
The more const, the better?
typedef boost::shared_ptr<int> shared_int_ptr;
const shared_int_ptr const p3; // ill-formed
The above typedef is provided to make it easier to see that boost::shared_ptr<int> is a single name, and therefore we cannot add const on both sides; duplicate consts are (as you mentioned) not legal C++.
Just applying one wouldn't be sufficient either, since that would make the wrapper const, but not the internal object that it is referring to (the int).
Previously we wrote that boost::shared_ptr should wrap around an int, but since we want to make the wrapped type const, well.. let's wrap the shared_ptr around what we want:
void func (const boost::shared_ptr<const int> foo);
In the above func is not able to modify foo, nor the int referred to by foo.
Function overloading can happen between two member functions which have the same number of parameters, if one of them is declared as const.
But what if one function has a const argument, another has non-const argument of same type?
Will it work for references and pointers? If C++ provides it, why does it provide? Please share the reason with me if you know.
Below is the example that helps you in understanding the above scenario.
void fun(const int i)
{
cout << "fun(const int) called ";
}
void fun(int i)
{
cout << "fun(int ) called " ;
}
int main()
{
const int i = 10;
fun(i);
return 0;
}
Output: Compiler Error: redefinition of 'void fun(int)'
void fun(char *a)
{
cout<<"non-const fun() called";
}
void fun(const char *a)
{
cout<<"const fun() called";
}
int main()
{
const char *ptr = "GeeksforGeeks";
fun(ptr);
return 0;
}
Output: const fun() called
Why is the second one allowed in C++?
The first one's parameters are top-level const. This means that the function can't change the parameter's value, however, the caller doesn't care: The callee gets a copy of the argument, so if a parameter has top-level const, it's an implementation detail. Note that the following works:
void f(int); // forward declare
void g(){ f(42); }
void f(int const i){ /*...*/ } // define above declared function
For the second set of overloads, the const isn't top-level anymore. It describes whether or not the callee can change what the pointer points at. As a caller, you do care about that. It's not just an implementation detail anymore.
First, explain why the first code is not allowed while the second one is ok.
const int and int as parameter, you pass any related type, double, int or anything else can convert to int, both const int and int can accept the pass-in value, there's no difference practically. And if the complier allow to the define both, then which one to call? You don't know, neither the complier. So the first part of code is not allowed.
When it comes to second example, reference and pointer makes a difference. Because you can't pass a const int* to initialize int * and neither can use const int to initialize int&. So if you define two functions with same return type, one is "const version" pointer or reference parameter, and the other is not, that makes a difference. Another question comes up, what if I pass a int object(or called variable, same meaning) or int * pointer, then which one is matched (when parameters are pointer or reference)? The answer is the "non-const" one. if you want to match the "const version" with non-const object or non point to const pointer, you may need const_cast which I am trying to figure out.
So back to your question:
But what if one function has a const argument, another has non-const argument of same type? Will it work for references and pointers?
Yes, it to some extent only works for reference and pointers.
And
If C++ provides it, why does it provide?
Can't tell. I don't have much experience.
For further information, read the very related part sections of C++ Primer 5th.
Links of screenshots are listed as follows:
https://imgur.com/tnqrxVY
https://imgur.com/hF1MjUH
https://imgur.com/Fg2zeEw
By the way, though I am a newbie. But what is int const i from the first answer? And I don't understand what "it's an implementation detail" exactly mean. No offense, just can't understand that part of answer. :D
I'm struggling to get my head around the differences between the various places you can put 'const' on a function declaration in c++.
What is the difference between const at the beginning:
const int MyClass::showName(string id){
...
}
And const at the end like:
int MyClass::showName(string id) const{
...
}
Also, what is the result of having const both at the beginning and at the end like this:
const int MyClass::showName(string id) const{
...
}
const int MyClass::showName(string id) returns a const int object. So the calling code can not change the returned int. If the calling code is like const int a = m.showName("id"); a = 10; then it will be marked as a compiler error. However, as noted by #David Heffernan below, since the integer is returned by copy the calling code is not obliged to use const int. It can very well declare int as the return type and modify it. Since the object is returned by copy, it doesn't make much sense to declare the return type as const int.
int MyClass::showName(string id) const tells that the method showName is a const member function. A const member function is the one which does not modify any member variables of the class (unless they are marked as mutable). So if you have member variable int m_a in class MyClass and if you try to do m_a = 10; inside showName you will get a compiler error.
Third is the combination of the above two cases.
The const attached to the return value applies to the return value. Since the return value is copied it's a pointless declaration and it makes no difference whether or not you include it.
The const after the parameter list means that the function does not modify any state of the object that is not marked as mutable. This is a const member function and if you have a const object the compiler will not allow you to call non-const member functions on a const object.
There is no interaction between these two uses of const - they are completely independent constructs
The difference is that the const applies to different things.
This says that showName returns a constant int value -- one that is immutable. Of course since the int is returned by value the presence of const here does not play any role.
const int MyClass::showName(string id)
And this says that showName does not modify the observable state of MyClass (technically: it does not modify any member that is not declared mutable), and therefore you are allowed to call it on a value of type const MyClass.
int MyClass::showName(string id) const
If you use both consts then both of the above apply.
Questions like this tend to strengthen my resolve to follow the advice of Dan Saks as outlined in this "Conversations with a Guru" article: http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835 .
In particular it deals with how the placement of const changes things. (*) I realize that I am extremely unlikely to convert anyone from writing const int ... to int const ..., but that said, there is one reason I prefer to do the latter.
(*) incuding a note that swapping the const with the type declaration at the very start is the one change that has no effect.
It makes for very easy readability, because for any instance of the word
const in a declaration, everything to the left of it is the type of what is const, and everything to the right is what actually is const.
Consider a declaration like:
int const * * const pointerToPointer;
The first const states that the integers at the end of the pointer chain are const, and they are to be found at * * const pointerToPointer. Meanwhile the second one states that an object of type pointer to pointer to const int is also const and that this object is pointerToPointer.
In the OP's case:
int const MyClass::showName(string id){
...
}
The type of what is const is int, and what is const is the return value from the function.
Meanwhile:
int MyClass::showName(string id) const {
...
}
Here the type of what is const is function(string) returning int, and what is const is the function itself, i.e. the function body.