The following code does not compile in gcc:
namespace One{
class A{
};
};
namespace Two{
class A{
public:
void what(){
cout << "Two::A says what!" << endl;
}
};
class B : public One::A{
public:
B(){
A xx;
xx.what();
}
};
};
And it gives:
gccbug.cpp: In constructor ‘Two::B::B()’:
gccbug.cpp:23: error: ‘class One::A’ has no member named ‘what’
Now, I was told that this is correct behavior (due to injected base name of One::A making A refer to One::A). However, this code compiles in C# (well, after changing a few things), so this seems to be c++ specific.
What I'm wondering is.. why? Is there a specific purpose for injecting the base name "One::A" as "A"?
The only reason I can think of is that in C++ you are likely to refer to the base class name in the initializer list of the constructor, like this:
namespace Two {
/*...*/
class B : public One::A {
public:
B():A()
{
/*...*/
}
};
}
Of course the purpose then is different from the one in your example, because you actually declare a local variable inside the constructor, whereas in my example, the A() refers to the object of type A that is implicit in the definition of class B due to inheritance.
However, the situation of my example is more likely to occur, so I guess they thought let's not require the namespace to be made explicit in this case. As a consequence, any reference to A without a namespace is interpreted as referring to the base class, rather than any other class named A, even if it is in the same namespace as the declaration of B.
Is there a specific purpose for injecting the base name "One::A" as "A"?
Yes. It is so that you could write this:
namespace N
{
class A
{
A *a;
};
}
In the absence of injected-name, you've to write N::A *a which is not nice.
Note that it is because of injected-name, the following lines are allowed:
A::A *a1; //ok
A::A::A *a2; //ok
A::A::A::A *a3; //ok
A::A::A::A::A *a4; //ok
//and so on
Online demo
By qualifying A with One:: you added the A from namespace one in scope, so the compiler will look there for it's name resolution.
Related
It is possible to write a using declaration to e.g. promote a private base class method to being public in a derived class, i.e. B::foo in the example. Is it possible to do something similar to make a method available without the need to write another method?
#include <iostream>
class A
{
int m_number{ 99 };
protected:
int foo() { return m_number; }
};
class B : public A
{
public:
using A::foo;
};
class C
{
B m_a;
public:
using foo() = m_a.foo(); // is something like this possible?
};
int main() {
B b;
std::cout<<b.foo();
C c;
std::cout<<c.foo();
}
It is not possible to do this. In order to understand why, you need to understand that the purpose of a using declaration is to affect the name lookup algorithm, by making a name appear somewhere else from where it was originally declared.
The declaration in B that reads:
using A::foo;
has the effect of causing the lookup for the name foo in the scope of B to find the member A::foo. It does not create a new foo method that takes B* as the this pointer and forwards the call to A::foo; it simply causes the function A::foo to appear elsewhere (that is, in B).
A using declaration cannot result in the generation of any new code, such as that which would be necessary to forward a call by invoking a method on a member. If you want a new method, you'll just have to write it yourself.
The following snippet produces an "ambigious call to foo" error during compilation, and I'd like to know if there is any way around this problem without fully qualifying the call to foo:
#include <iostream>
struct Base1{
void foo(int){
}
};
struct Base2{
void foo(float){
}
};
struct Derived : public Base1, public Base2{
};
int main(){
Derived d;
d.foo(5);
std::cin.get();
return 0;
}
So, question is as the title says. Ideas? I mean, the following works flawlessly:
#include <iostream>
struct Base{
void foo(int){
}
};
struct Derived : public Base{
void foo(float){
}
};
int main(){
Derived d;
d.foo(5);
std::cin.get();
return 0;
}
Member lookup rules are defined in Section 10.2/2
The following steps define the result of name lookup in a class scope, C. First, every declaration for the name in the class and in each of its base class sub-objects is considered. A member name f in one sub-object B hides a member name f in a sub-object A if A is a base class sub-object of B. Any declarations that are so hidden are eliminated from consideration. Each of these declarations that was introduced by a using-declaration is considered to be from each sub-object of C that is of the type containing the declara-tion designated by the using-declaration. If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed. Otherwise that set is the result of the lookup.
class A {
public:
int f(int);
};
class B {
public:
int f();
};
class C : public A, public B {};
int main()
{
C c;
c.f(); // ambiguous
}
So you can use the using declarations A::f and B::f to resolve that ambiguity
class C : public A, public B {
using A::f;
using B::f;
};
int main()
{
C c;
c.f(); // fine
}
The second code works flawlessly because void foo(float) is inside C's scope. Actually d.foo(5); calls void foo(float) and not the int version.
Name lookup is a separate phase to overload resolution.
Name lookup occurs first. That is the process of deciding which scope the name applies to. In this case we must decide whether d.foo means d.D::foo, or d.B1::foo, or d.B2::foo. The name lookup rules do not take into account function parameters or anything; it is purely about names and scopes.
Only once that decision has been made, do we then perform overload resolution on the different overloads of the function in the scope where the name was found.
In your example, calling d.foo() would find D::foo() if there were such a function. But there is none. So, working backwards up the scopes, it tries the base classes. Now foo could equally look up to B1::foo or B2::foo so it is ambiguous.
For the same reason, you would get ambiguity calling unqualified foo(5); inside a D member function.
The effect of the recommended solution:
struct Derived : public Base1, public Base2{
using Base1::foo;
using Base2::foo;
is that this creates the name D::foo, and makes it identify two functions. The result is that d.foo resolves to d.D::foo, and then overload resolution can happen on these two functions that are identified by D::foo.
Note: In this example D::foo(int) and Base1::foo(int) are two identifiers for the one function; but in general, for the name lookup and overload resolution process, it doesn't make a difference whether they are two separate functions or not.
Will it work for you?
struct Derived : public Base1, public Base2{
using Base2::foo;}
The following snippet produces an "ambigious call to foo" error during compilation, and I'd like to know if there is any way around this problem without fully qualifying the call to foo:
#include <iostream>
struct Base1{
void foo(int){
}
};
struct Base2{
void foo(float){
}
};
struct Derived : public Base1, public Base2{
};
int main(){
Derived d;
d.foo(5);
std::cin.get();
return 0;
}
So, question is as the title says. Ideas? I mean, the following works flawlessly:
#include <iostream>
struct Base{
void foo(int){
}
};
struct Derived : public Base{
void foo(float){
}
};
int main(){
Derived d;
d.foo(5);
std::cin.get();
return 0;
}
Member lookup rules are defined in Section 10.2/2
The following steps define the result of name lookup in a class scope, C. First, every declaration for the name in the class and in each of its base class sub-objects is considered. A member name f in one sub-object B hides a member name f in a sub-object A if A is a base class sub-object of B. Any declarations that are so hidden are eliminated from consideration. Each of these declarations that was introduced by a using-declaration is considered to be from each sub-object of C that is of the type containing the declara-tion designated by the using-declaration. If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed. Otherwise that set is the result of the lookup.
class A {
public:
int f(int);
};
class B {
public:
int f();
};
class C : public A, public B {};
int main()
{
C c;
c.f(); // ambiguous
}
So you can use the using declarations A::f and B::f to resolve that ambiguity
class C : public A, public B {
using A::f;
using B::f;
};
int main()
{
C c;
c.f(); // fine
}
The second code works flawlessly because void foo(float) is inside C's scope. Actually d.foo(5); calls void foo(float) and not the int version.
Name lookup is a separate phase to overload resolution.
Name lookup occurs first. That is the process of deciding which scope the name applies to. In this case we must decide whether d.foo means d.D::foo, or d.B1::foo, or d.B2::foo. The name lookup rules do not take into account function parameters or anything; it is purely about names and scopes.
Only once that decision has been made, do we then perform overload resolution on the different overloads of the function in the scope where the name was found.
In your example, calling d.foo() would find D::foo() if there were such a function. But there is none. So, working backwards up the scopes, it tries the base classes. Now foo could equally look up to B1::foo or B2::foo so it is ambiguous.
For the same reason, you would get ambiguity calling unqualified foo(5); inside a D member function.
The effect of the recommended solution:
struct Derived : public Base1, public Base2{
using Base1::foo;
using Base2::foo;
is that this creates the name D::foo, and makes it identify two functions. The result is that d.foo resolves to d.D::foo, and then overload resolution can happen on these two functions that are identified by D::foo.
Note: In this example D::foo(int) and Base1::foo(int) are two identifiers for the one function; but in general, for the name lookup and overload resolution process, it doesn't make a difference whether they are two separate functions or not.
Will it work for you?
struct Derived : public Base1, public Base2{
using Base2::foo;}
Can you explain why this is not allowed,
#include <stdio.h>
class B {
private:
int a;
public:
int a;
};
int main() {
return 0;
}
while this is?
#include <stdio.h>
class A {
public:
int a;
};
class B : public A{
private:
int a;
};
int main() {
return 0;
}
In both the cases, we have one public and one private variable named a in class B.
edited now!
In both the cases, we have one public
and one private variable named a in
class B.
No, thats not true.
In the first case, you can't have two identifiers with the same name in the same scope. While in the second case, B::a hides A::a, and to access A::a you have to fully qualify the name:
b.a = 10; // Error. You can't access a private member.
b.A::a = 10; // OK.
Because B::a hides A::a in the second example. You can still access it, but it needs explicit qualification for the compiler to figure out you are asking for the member of parent class with the same hame.
In the first example both a's are in the same scope, while in the second example the scopes are different.
Class B in the first example is not valid because C++ cannot distinguish members by their access specifiers (public/private/protected). However, namespaces are a way for C++ to distinguish members. In class B in the second code you don't have a "public a" and a "private a", you have B::a and A::a.
Even if declaring members of the same name/signature with different access specifiers was allowed, there would be no way to address the correct member.
The first isn't allowed because it leads to ambiguous definitions. In the 2nd, although you do have both a public and a private a integer variable, you've hidden A::a inside your B class. The compiler knows implicitly what you want because there is a way to explicitly access a hidden variables.
I also believe that it boils down to name mangaling: storage specifiers don't end up as part of the actual name. I could be wrong on this however.
The easiest way to illustrate why one is allowed and why the other isn't is to look at how the compiler would compile a member function that uses each variable.
Inside your class b:
class b {
int a;
public:
int a;
void myMethod()
{
a = 10; //what a should the compiler use? Ambiguous, so the compiler sez BZZT.
}
}
For the 2nd example:
class A
{
public:
int a;
}
class B: public A
{
private:
int a;
void someMethod()
{
a = 10; //implied that you are using B::a (which may be a programmer error)
}
}
This question already has answers here:
Function with same name but different signature in derived class not found
(2 answers)
Closed 8 years ago.
Given the following example, why do I have to explicitly use the statement b->A::DoSomething() rather than just b->DoSomething()?
Shouldn't the compiler's overload resolution figure out which method I'm talking about?
I'm using Microsoft VS 2005. (Note: using virtual doesn't help in this case.)
class A
{
public:
int DoSomething() {return 0;};
};
class B : public A
{
public:
int DoSomething(int x) {return 1;};
};
int main()
{
B* b = new B();
b->A::DoSomething(); //Why this?
//b->DoSomething(); //Why not this? (Gives compiler error.)
delete b;
return 0;
}
The two “overloads” aren't in the same scope. By default, the compiler only considers the smallest possible name scope until it finds a name match. Argument matching is done afterwards. In your case this means that the compiler sees B::DoSomething. It then tries to match the argument list, which fails.
One solution would be to pull down the overload from A into B's scope:
class B : public A {
public:
using A::DoSomething;
// …
}
Overload resolution is one of the ugliest parts of C++
Basically the compiler finds a name match "DoSomething(int)" in the scope of B, sees the parameters don't match, and stops with an error.
It can be overcome by using the A::DoSomething in class B
class A
{
public:
int DoSomething() {return 0;}
};
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;}
};
int main(int argc, char** argv)
{
B* b = new B();
// b->A::DoSomething(); // still works, but...
b->DoSomething(); // works now too
delete b;
return 0;
}
No, this behaviour is present to ensure that you don't get caught out inheriting from distant base classes by mistake.
To get around it, you need to tell the compiler which method you want to call by placing a using A::DoSomething in the B class.
See this article for a quick and easy overview of this behaviour.
The presence of a method in a derived class hides all methods with the same name (regardless of parameters) in base classes. This is done to avoid problems like this:
class A {} ;
class B :public A
{
void DoSomething(long) {...}
}
B b;
b.DoSomething(1); // calls B::DoSomething((long)1));
than later someone changes class A:
class A
{
void DoSomething(int ) {...}
}
now suddenly:
B b;
b.DoSomething(1); // calls A::DoSomething(1);
In other words, if it didn't work like this, a unrelated change in a class you don't control (A), could silently affect how your code works.
This has something to do with the way name resolution works. Basically, we first find the scope from which the name comes, and then we collect all overloads for that name in that scope. However, the scope in your case is class B, and in class B, B::DoSomething hides A::DOSomething:
3.3.7 Name hiding [basic.scope.hiding]
...[snip]...
3 In a member function definition, the declaration of a local name hides
the declaration of a member of the class with the same name; see
basic.scope.class. The declaration of a member in a derived class
(class.derived) hides the declaration of a member of a base class of
the same name; see class.member.lookup.
Because of name hiding, A::DoSomething is not even considered for overload resolution
When you define a function in a derived class then it hides all the functions with that name in the base class. If the base class function is virtual and has a compatible signature then the derived class function also overrides the base class function. However, that doesn't affect the visibility.
You can make the base class function visible with a using declaration:
class B : public A
{
public:
int DoSomething(int x) {return 1;};
using A::DoSomething;
};
That's not overloading! That's HIDING!
When searching up the inheritance tree for the function to use, C++ uses the name without arguments, once it has found any definition it stops, then examines the arguments. In the example given, it stops in class B. In order to be able to do what you are after, class B should be defined like this:
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;};
};
The function is hidden by the function with the same name in the subclass (but with a different signature). You can unhide it by using the using statement, as in using A::DoSomething();