A C++ guru told that varying the function parameter type with const in derived class, will break the virtual call mechanism.
I tried a simple program ( forgive for non standard code, written purely for test) , which prove otherwise. The function parameter change by const value will not break the virtual mechanism,
Is there any reasons & documentation pointing to this behavior?
Behavior noted with VS 2012 compiler & latest g++ compiler.
#include <iostream>
using namespace std;
class Base
{
public:
Base(){ cout<<"base"<<endl;}
virtual ~Base(){ cout<<"dest base"<<endl;}
virtual void test(const int x){ cout << "base test"<<"x = " << x<<endl;}
};
class Derived : public Base
{
public:
Derived(){ cout<<"derived"<<endl;}
virtual ~Derived(){ cout<<"dest derived"<<endl;}
virtual void test(int x){ cout << "derived test"<<"x = " << x<<endl;}
};
int main() {
Base *b = new Derived();
b->test(10);
delete b;
return 0;
}
output:
base
derived
derived testx = 10
dest derived
dest base
void test(int)
!=void test(int) const
and would "break" virtual call.and
void test(int&)
!=void test(const int&)
and would "break" virtual call.void test(int)
is the same declaration thanvoid test(const int)
and won't "break" virtual call.He was right.just found it by seeing the warning.
In this case : Compilers before VS2008 would break the virtual mechanism in this case.
Later compilers it gives warning C4373: virtual function overrides '%$pS', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers
found the documentation here https://msdn.microsoft.com/en-us/library/bb384874.aspx
Your
C++ guru
is wrong (provided you understood them, gurus tend to talk in cryptic messages).Const
-qualifier on the argument type itself is not a part of a function signature at all.For example,
void foo(int* const );
is no different fromvoid foo(int* )
. Please note, it is not the same as const qualification of the indirect object, likevoid foo(const int* )
is different fromvoid foo(int* )
.In your particular case,
void test(int x)
is the same asvoid test(int const x)
The equivalent of std::decay happens to argument types for functions. (It's actually the reverse, std::decay is modeled after what functions arguments do.)
The outermost const will be dropped from the signature. By outermost, think of types as envelopes composed over different types. A pointer to const int is a different type than a pointer to int, and will result in a different function signature. (With a pointer, you can think of the pointer itself as the outer thing, and what it points to is "inner" and not modified.)
const int
- becomes justint
int *
is unchanged and remainsint *
const int *
is unchanged and remainsconst int *
- const is on the int, not the pointer, and only the outermost const is droppedint const *
is unchanged and remainsint const *
- const is on the int, not the pointer, and only the outermost const is dropped. (Note, this is 100% identical in meaning asconst int *
)int * const
- changes toint *
- because const qualifies the outermost pointerint * const * const
becomesint * const *
- outer const is dropped on outer pointer, inner const is not dropped on the inner pointer.const int * const * const
becomesconst int * const *
- outer const is dropped on outer pointer, inner const is not dropped on the inner pointer, and const is also kept on the internal-most intMyTemplate<const T>
- unchanged, remainsMyTemplate<const T>
, because the const isn't on the outer type, but nestled in a template parameterSo yes, const does affect type, but not in the simple case like you tried. Only when it's contained inside of a type, not affecting the outermost type.
If you read types from right-to-left it can help. If the rightmost thing in a type specifier is a const, it is always dropped (example
int * const
). If the leftmost thing is const, it is only dropped if the thing it is qualifying is the rightmost thing in the type (exampleconst int
, the leftmost thing is const and it affects the int to its right AND the int to its right is the rightmost thing in the type.) (example 2:const * int
not dropped, because leftmost const modifies the thing to its right that is not the rightmost thing in the type.)The top level cv-qualifier is not part of function signature, they are simply ignored.
[dcl.fct]/5