C++ overload resolution [duplicate] - c++

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();

Related

Why is inheritance of a const/non-const function overload ambiguous?

I was trying to create two classes, the first with a non-const implementation of the functions, the second with a const implementation. Here is a small example:
class Base {
protected:
int some;
};
class A : public virtual Base {
const int& get() const {
return some;
}
};
class B : public virtual Base {
int& get() {
return some;
}
};
class C : public A, B {};
C test;
test.get(); // ambiguous
The call to the get function is ambiguous. No matter that the const version needs to match more requirements. (Calling get on const C is ambiguous as well, but there is one possible function to call.)
Is there a reason for such behaviour in the standard? Thanks!
Ambiguity occurs when compiler tries to figure out to what entity does the name get refer to, prior to overload resolution. It can be a name of function from class A or from class B. In order to build a list of overloads complier needs to select just one of the classes to pull functions from. In order to fix it you can bring that name from both of the base classes into derived class (and make them public):
class C : public A, public B { public: using A::get; public: using B::get; };
The problem is that you don't actually have one unified overload-set, in which the mutable variant would be unambiguously best, but two distinct overload-sets, in A and B, and the compiler will not automatically merge them.
Put
using A::get;
using B::get;
in C to merge the overload-sets and thus resolve the ambiguity.

Is it possible to write a using declaration for a method of a member, similar to a inherented method?

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.

C++11 use variadic subclass when they are template [duplicate]

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;}

why I changed parent virtual function arguments in child hides the father function c++?

I made a class with virtual function f() then in the derived class I rewrote it like the following f(int) why can't I access the base class function throw the child instance ?
class B{
public:
B(){cout<<"B const, ";}
virtual void vf2(){cout<<"b.Vf2, ";}
};
class C:public B{
public:
C(){cout<<"C const, ";}
void vf2(int){cout<<"c.Vf2, ";}
};
int main()
{
C c;
c.vf2();//error should be vf2(2)
}
You have to do using B::vf2 so that the function is considered during name lookup. Otherwise as soon as the compiler finds a function name that matches while traversing the inheritance tree from child -> parent -> grand parent etc etc., the traversal stops.
class C:public B{
public:
using B::vf2;
C(){cout<<"C const, ";}
void vf2(int){cout<<"c.Vf2, ";}
};
You are encountering name hiding. Here is an explanation of why it happens ?
In C++, a derived class hides any base class member of the same name. You can still access the base class member by explicitly qualifying it though:
int main()
{
C c;
c.B::vf2();
}
You were caught by name hiding.
Name hiding creeps up everywhere in C++:
int a = 0
int main(int argc, char* argv[]) {
std::string a;
for (int i = 0; i != argc; ++i) {
a += argc[i]; // okay, refers to std::string a; not int a;
a += " ";
}
}
And it also appears with Base and Derived classes.
The idea behind name hiding is robustness in the face of changes. If this didn't exist, in this particular case, then consider what would happen to:
class Base {
};
class Derived: public Base {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
Derived d;
d.foo(1.0);
}
If I were to add a foo overload to Base that were a better match (ie, taking a double directly):
void Base::foo(double i) {
sleep(i);
}
Now, instead of printing 1, this program would sleep for 1 second!
This would be crazy right ? It would mean that anytime you wish to extend a base class, you need to look at all the derived classes and make sure you don't accidentally steal some method calls from them!!
To be able to extend a base class without ruining the derived classes, name hiding comes into play.
The using directive allows you to import the methods you truly need in your derived class and the rest are safely ignored. This is a white-listing approach.
When you overload a member function in a base class with a version in the derived class the base class function is hidden. That is, you need to either explicitly qualify calls to the base class function or you need a using declaration to make the base class function visible via objects of the derived class:
struct base {
void foo();
void bar();
};
struct derived: base {
void foo(int);
using base::foo;
void bar(int);
};
int main() {
derived().foo(); // OK: using declaration was used
derived().bar(); // ERROR: the base class version is hidden
derived().base::bar(); // OK: ... but can be accessed if explicitly requested
}
The reason this is done is that it was considered confusing and/or dangerous when a member function is declared by a derived function but a potenially better match is selected from a base class (obviously, this only really applies to member functions with the same number of arguments). There is also a pitfall when the base class used to not have a certain member function: you don't want you program to suddenly call a different member function just because a member function is being added to the base class.
The main annoyance with hiding member functions from bases is when there is a set of public virtual functions and you only want to override one of them in a derived class. Although just adding the override doesn't change the interface using a pointer or a reference to the base class, the derived class can possibly not used in a natural way. The conventional work-around for this to have public, non-virtual overload which dispatch to protected virtual functions. The virtual member function in the various facets in the C++ standard library are an example of this technique.

Syntax for class within a class in C++

If I have the following
class A
{
public:
int stuff;
void helper(B temp, int d); //what about here? I'm getting a 'B' has not been declared error here.
private:
class B
{
public:
int stuffer;
private:
int x;
};
}:
Whats the correct way to refer to class 2 in my implementation file? Would it be
1::2::someMethod? Or 2::someMethod?
Assuming that 1 and 2 refer to REAL class names, 1::2::methodName just like any other nested scoping.
First of all, class name cannot start with integer. So renaming them:
class A
{
public:
int stuff;
private:
class B
{
public:
int stuffer;
private:
int x;
};
};
Second, since the nested class B is in the private section, so you cannot access it from outside the scope of class A. B is accessible to A only. And the syntax of declaring an object of type B would be B bObj; in the scope of A.
Now you should try yourself first, before asking futher questions!
As for your edit (the added question): it's not compiling because by the time the compiler sees B temp, it has not yet seen the definition of B, that is why it says B is not declared!
The fix is very simple. Declare B before it's used, something like this:
class A
{
private:
class B
{
public:
int stuffer;
private:
int x;
};
public:
int stuff;
void helper(B temp, int d);
}; //<--- this is also fixed. your code has 'colon', instead semi-colon!
Also read the comment at the end of the class!
If you're inside a method of class 1, you can use 2::somemethod. In other places, use 1::2::somemethod. "Inside" includes method argument declarations in method implementations of class 1, but not return value declarations for method implementations of class 1.
It depends on which scope level you're at. Inside a member function for class 1, it would be class_2::someMethod. At file scope, it would be class_1::class_2::someMethod. It's always correct to fully qualify a function or variable name like that, but sometimes it's more typing than is strictly necessary. In general, you need the scope resolution operator :: when the compiler can't figure out on its own what you're referring to.
In practice, the best way to find out is try it and see what happens. If the compiler gives you an error, throw the class name in front of it and try again.
Syntax for nested class:
Class class_name1
{
Private:
Data members
Public:
Member functions
{
.........
}
Class class_name2 //class2 is embedded with class1
{
Private:
Data members
Public:
Member functions
{
.........
}
}; // class2
}; //class1
Nested class is possible to define one class within another class since a class declaration does,define a scope.
A nested class is valid only within the scope of the enclosing class.
Need of nested class is virtually not existed.