tags:

views:

912

answers:

7

If I do this:

// In header 
class Foo {
void foo(bar*);
};

// In cpp
void Foo::foo(bar* const pBar) {
//Stuff
}

The compiler does not complain that the signatures for Foo::foo do not match. However if I had:

void foo(const bar*); //In header
void Foo::foo(bar*) {} //In cpp

The code will fail to compile.

What is going on? I'm using gcc 4.1.x

+15  A: 

In the first, you've promised the compiler, but not other users of the class that you will not edit the variable.

In your second example, you've promised other users of the class that you will not edit their variable, but failed to uphold that promise.

I should also note that there is a distinct difference between

bar* const variable

and

const bar* variable

and

const bar* const variable

In the first form, the pointer will never change, but you can edit the object that is pointed to. In the second form, you can edit the pointer(point it to another object), but never the variable that it points to. In the final form, you will neither edit the pointer, nor the object it points to. Reference

To add a bit more of a clarification to the question stated, you can always promise MORE const than less. Given a class:

class Foo {
    void func1 (int x);
    void func2 (int *x);
}

You can compile the following implementation:

Foo::func1(const int x) {}
Foo::func2(const int *x) {}

or:

Foo::func1(const int x) {}
Foo::func2(const int* const x) {}

without any problems. You've told your users that you may possibly edit their variables. In your implementation, you've told the compiler that this particular implementation will not edit those variables, even though the told the users you might. You haven't broken a promise to the user, and so the code compiles.

Douglas Mayle
I don't think your theory holds: 1) If you declare "int*" and implement "const int*", as in your example, it does not compile. 2) If you pass by value, you can declare const and not implement with const. It does not have meaning when you pass by value.
Dusty Campbell
yes. i agree you are wrong. void f(int const*); is different from void f(int *); i think you wanted to write void f(int * const); has the same signature as void f(int *); you should change your example since it could confuse beginners.
Johannes Schaub - litb
A: 

In the former, the const doesn't affect the interface, only the implementation. You are saying to the compiler, "I am not going to change the value of the bar* within this function". You can still change what is pointed to by the pointer. In the latter, you are telling the compiler (and all callers) that you will not change the bar structure that the bar* points to.

Greg Hewgill
I think you mean in the last sentence "you will not modify the bar that the bar* points to". "Change what the bar* points to" might be taken to mean "give the bar* a new value", which is of course fine in the second example.
Steve Jessop
Thanks for that, fixed. Pronouns are the bane of clarity.
Greg Hewgill
+6  A: 

See this question, this question, and this question.

Basically, the const only means that the function will not modify the pointer's value. The pointers contents are not const, the same as the header's signature.

Greg Rogers
A: 

So the second const in:

void Foo::foo(const bar* const);

Is not part of the method signature?

anio
You declare a method in the .h file, you define it in the .cpp. Everything in the declaration is part of the signature (both consts), it appears that in the definition you can more closely refine the argument type as long as that definition does not break the semantics of the declaration.
Scott Langham
@mamin: Correct. For example, look at the linker error you get if you declare (but don't define) a function "void foo(const int* const a)", and then call it. The signature reported missing by GCC is "foo(int const*)".
Steve Jessop
simple: if you add/remove const it will not be part of the signature. so void foo(int*const); and void foo(int*); do indeed have the same signature. BUT void foo(int const*); and void foo(int*); do have different signatures: there is no const added to the parameter type, but to the type pointed to.
Johannes Schaub - litb
+1  A: 

The const keyword in the first example is meaningless. You are saying that you don't plan on changing the pointer. However, the pointer was passed by value and so it dos not matter if you change it or not; it will not effect the caller. Similarly, you could also do this:

// In header 
class Foo {
void foo( int b );
};

// In cpp
void Foo::foo( const int b ) {
//Stuff
}

You can even do this:

// In header 
class Foo {
void foo( const int b );
};

// In cpp
void Foo::foo( int b ) {
//Stuff
}

Since the int is passed by value, the constness does not matter.

In the second example you are saying that your function takes a pointer to one type, but then implement it as taking a pointer to another type, therefore it fails.

Dusty Campbell
A: 

This is simpler to understand with a variable type other than a pointer. For example, you can have the following function declaration:

void foo( int i );

The definition can look like this:

void foo( const int i ) { ... }

Whether the variable 'i' is const or not on the definition side is an implementation detail. It has no impact for the clients of that function.

Martin Cote
i don't get how SO users vote. top voted with +15 above is an answer that has a wrong statement at the end and doesn't feel like fixing it (ppl told it to him 3 months ago), and at -1 was this answer that's all right and explained much better (IMHO). doing +1 for the sake of fairness.
Johannes Schaub - litb
Agreed. I don't understand why I was downvoted for this answer...
Martin Cote
A: 

It probably doesn't care much about void Foo::foo(bar* const pBar) because how you treat the pointer itself (const or not) doesn't matter one bit outside of the routine. The C rules say that no change to pBar will travel outside of foo either way.

However, if it is (const bar* pBar), that makes a difference, because it means the compiler is not to allow callers to pass in pointers to non-const objects.

T.E.D.