Take the following class for an example
class A
{
int m_c;
public:
void B(int C);
void C();
};
This would give out the following warning if i compiled with the -Wshadow argument
memberFuncArg.cpp: In member function ‘void A::B(int)’:
memberFuncArg.cpp:12:16: warning: declaration of ‘C’ shadows a member of 'this' [-Wshadow]
void A::B(int C)
^
What are the consequences of shadowing a member function with an argument to another member function like this?
What are the consequences of shadowing a member function with an argument
The consequence is that a programmer who reads the code may be confused about which entity is being referred to by C. They may have become accustomed to the fact that C is a member function, and reasonably (but mistakenly) expect this to be the case within B as well.
The consequence is much worse when the argument is not of type int, but of some other type that can be invoked with same arguments as the member function. The confused programmer would then read or write C() and expect it to call the member function, but the behaviour would be different than expected.
Related
Running the code below in g++ will result the following error:
error: passing 'const A' as 'this' argument discards qualifiers [-fpermissive]
struct A{
void f(){};
};
int main(){
const A a;
a.f();
return 0;
}
Where do we use this?
fpermissive implies that the code is non-conformant.
Where does the standard states that this is an error?
The standard covers this in [class.this]. In particular, see example 2, where it says (in part):
The call y.g() is ill-formed because y is const and s::g() is a non-const member function.
When applied to your code, the equivalent statement is:
The call a.f() is ill-formed because a is const and A::f() is a non-const member function.
To be clearer: A::f() is non-const because it lacks a const qualification; whether or not f() would be a legal const function (if the const qualification was added) is not relevant.
Perhaps what you are really interested in, though, is the first part of [class.this], where it states that the keyword this has a meaning in every non-static member function, regardless of whether or not this is ever used in that function.
I have a class A that accepts class B as a constructor parameter. Class B can be constructed from int value. My original code is quite complex, but I hope I've reduced it to the very base case:
class B {
public:
explicit B(int a) : val(a) {}
private:
int val;
};
class A {
public:
A(const B & val) : value(val) {};
void print() {
//does nothing
}
private:
B value;
};
int main() {
int someTimeVar = 22;
A a(B(someTimeVar));
a.print();
}
And this is the error code I'm getting:
$ g++ test.cpp -Wall -O0
test.cpp: In function ‘int main()’:
test.cpp:22:7: error: request for member ‘print’ in ‘a’, which is of non-class type ‘A(B)’
a.print();
^
test.cpp:20:9: warning: unused variable ‘someTimeVar’ [-Wunused-variable]
int someTimeVar = 22;
^
I use GCC (4.9.2 20150304 (prerelease)), platform: arch linux.
The following modification to the main function compiles fine:
int main() {
A a(B(22));
a.print();
}
I'm well aware that using A a(); declares a function, not a object. But I didn't expect that A a(B(some_val)) will do the same, and in my opinion this is what's happening here.
Do you have ideas why this is happening?
Edit: Thank you for all the answers, looks like I need to research more on most vexing parse idea.
BTW it turns out that compiling my code using clang provides more useful error message plus a solution:
$ clang test.cpp
test.cpp:21:8: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
A a(B(someTimeVar));
^~~~~~~~~~~~~~~~
test.cpp:21:9: note: add a pair of parentheses to declare a variable
A a(B(someTimeVar));
^
( )
test.cpp:22:6: error: member reference base type 'A (B)' is not a structure or union
a.print();
~^~~~~~
1 warning and 1 error generated.
A a(B(someTimeVar)) is interpreted as A a(B someTimeVar), so a is a function taking parameter of type B and returning A.
This is one of the reasons the uniform initialization was added to C++11:
A a{B{someTimeVar}};
This problem has its own tag here on stackoverflow. most-vexing-parse
Wikipedia har a clear description of the problem and its solution. https://en.wikipedia.org/wiki/Most_vexing_parse.
The line
TimeKeeper time_keeper(Timer());
could be disambiguated either as
a variable definition for variable time_keeper of class TimeKeeper, passed an anonymous instance of class Timer or
a function declaration for a function time_keeper which returns an object of type TimeKeeper and has a single (unnamed) parameter which
is a function returning type Timer (and taking no input). (See
Function object#In C and C++)
Most programmers expect the first, but the C++ standard requires it to
be interpreted as the second.
The solution is to add parenthesis to the argument like:
A a( (B(22)) );
or as others have noted use universal initialization like
A a { B{22} };
A a(B(someTimeVar)); declares a function with the return type A and one argument of type B named someTimeVar. It's the same as A a(B someTimeVar);
It works in A a(B(22)); because 22 is not a valid identifier, so the functio declaration would be invalid.
If your codebase uses C++11 (or newer), you can use uniform initialization with curly braces: A a(B{someTimeVar});
What is the reason why pointers to member functions, can't point to const member functions?
struct A {
void g() {};
void f() const {}
};
Later in code:
void (A::* fun)() = &A::f;
This code produces:
error: cannot convert ‘void (A::*)()const’ to ‘void (A::*)()’ in initialization
Of course it compiles with &A::g instead of &A::f.
In opposite situation:
void (A::* fun)() const = &A::g;
The error is:
error: cannot convert ‘void (A::*)()’ to ‘void (A::*)()const’ in initialization
The second case is rather clear. const pointer isn't expected to modify the object so it can't hold the function which does it. But why it's not possible to assign const member function to non-const member function as in the first case?
It looks like the rule for normal pointers where casting const to non-const would allow to modify the value, but I don't see the point here, where const-correctness is checked in function definition, before such assignment.
What is the reason why pointers to member functions, can't point to const member functions?
Because the const modifier is part of the function signature. Once you declare a function pointer, that function pointer can only be used to assign pointers to function that have the same function signature.
Non-static member functions have an extra hidden this parameter. Given the existence of that that extra hidden parameter, a non-static void A::f() const; behaves much like void A__f(const A *__this), and the behaviour you see for member functions models the behaviour for non-member functions.
void f(void *);
void (*pf)(const void *) = f; // also an error
As for whether it could break on any implementation, I suppose in theory, an implementation is permitted to read a void * parameter from a different register than a const void * parameter, and if so, the result of the conversion (were it valid) could not be used to call f properly. I have no idea why any implementor would make such a decision, and I don't know of any real implementation that does so, but it's one allowed by the standard.
I am reading some C++ text from the address https://cs.senecac.on.ca/~chris.szalwinski/archives/btp200.081/content/overl.html.
in the first lines, they say:
The signature of a member function consists of:
the function name,
the data types of its parameters,
the order of the parameters and
possibly
the const status of the function.
I don't understand what they mean by saying "the const status of the function".
Can anyone elaborate on that, please?
Thanks.
In C++, you can declare a member function of a class to be const, by appending that keyword to its signature (for instance, int MyClass:doSomething(int param) const {...}). Doing so guarantees that the function won't change the (non-mutable) members of the class object on which the function is called - and hence it can be called with const instances of that class.
It is permissible to have two different member functions for a class whose signature differs only in whether they are declared const or not.
They mean to sum up the items of where functions must differ in order to be put into the same class scope. The const at the end is:
struct A {
void f();
void f() const;
};
These are valid overloads. The first is called if you call f on a A, and the second is used if you call it on a const A:
A a;
a.f(); // takes first
A const& b = a;
b.f(); // takes second
Note that the term "signature" is misused here. The signature of a function is more broad, and includes also the class of which a function is a member of. A signature uniquely identifies a function.
Declaring a member function as const tells the compiler that the member function will not modify the object's data and will not invoke other member functions that are not const.
The compiler will check to make sure that you really don't modify the data. You can call a const member function for either a const or a non-const object, but you can't call a non-const member function for a const object (because it could modify the object).
You can read more about constness in C++ here.
The following is a common typo with language newcomers, who think that they are defining an object but are actually declaring a function:
struct T
{
void foo() {}
};
int main()
{
T obj();
obj.foo();
}
GCC 4.1.2's error is:
In function 'int main()':
Line 9: error: request for member 'foo' in 'obj', which is of non-class type 'T ()()'
compilation terminated due to -Wfatal-errors.
Why is the reported type in the message T ()()? I'd have expected T ().
IIRC this is just a compiler bug. GCC 4.4 says T() while 4.2 says T()() for me.
The error is best understood when you realize that you usually don't write out function types without naming at least the function, but it's a bit more common for function pointers.
For instance, int (*fooPtr)() names the pointer. If you omit the name, you have int (*)(). Now, going from function pointer to function type would give you int ()().
There's no real standard here, because ISO C++ doesn't define canonical names for all types. For instance, const volatile int is the same type as volatile const int, and neither form is canonical.