Please look at the following code:
#include <iostream>
using namespace std;
class A {
public:
A() {};
virtual void foo(double d) { cout << d << endl; }
virtual void foo(double d, int a) = 0;
};
class B : public A {
public:
B() {};
virtual void foo(double d, int a) { cout << d << endl << a << endl; }
};
int main()
{
B b;
b.foo(3.14);
return 0;
}
The compiler (tried g++ and visual c++ 2008) says that there's no function like B:foo(double). The exact message of g++ is:
main.cpp:21: error: no matching function for call to ‘B::foo(double)’
It looks like the effect of hiding rule, but in my opinion the rule should not be used here, since I'm not overriding foo(double) and both foo methods are defined in base class.
I know that I can fix the problem with
using A::foo;
declaration in the derived class B.
Can you explain why the code does not compile and what rules of C++ apply here?
The hiding rule is not about overriding, it is about hiding of names. If the derived class declares a member function, this hides other base class member functions with the same name. This also happens in your case.
Names shadow, not specific functions. Once you make a foo in B, all base foo's (note, by name!) are shadowed.
When the compiler encounters an identifier, the lookup rules kick in and start searching for that identifier. In your concrete situation, with b.foo, the compiler knows that foo must be a member of B or one of its subclasses. The lookup rules state that the compiler must start with the most derived class (considering the static type of the object) and follow up in the hierarchy, and that once the identifier is found in one level only definitions in that level will be considered, it must not keep looking upwards.
B& f(); // might return a B or something derived from B
void test() {
B& b = f(); // static type is B
b.foo(1.0);
}
Regardless of what f returns, the static type is B, so the compiler will lookup in B class and find B::foo(double,int). Since there is no other foo declaration at that level, the compiler must try to match (and fail) the function call with the available method declarations.
The important thing is that the lookup does not look the object but rather looks by type and going upwards, cutting as soon as it encounters the first instance.
Looks perfectly reasonable to me. Although function signature does matter to know what the function is, I can see how this behavior prevents very stupid mistakes.
As ereOn suggested, using directive would be a fair price to pay.
Related
I've tried to map it out in my head, but honestly I have no idea what's really going on here.
What exactly is happening when I add and remove the virtual keyword from the below example?
#include <iostream>
#include <string>
class A {
public:
A() { me = "From A"; }
void caller() { func(); }
virtual void func() { std::cout << me << std::endl; } // THIS LINE!
private:
std::string me;
};
class B : public A {
public:
B() { me = "From B"; }
void func() { std::cout << me << std::endl; }
private:
std::string me;
};
int main() {
A a;
a.caller();
B b;
b.caller();
return 0;
}
With the virtual keyword, it prints "From A", then "From B".
Without the virtual keyword, it prints "From A", then "From A".
So far, this is the only time I've found a use for virtual functions without pointers being involved. I thought that if the virtual keyword was removed, the compiler would do the standard thing which is to overload the inherited function and end up printing "From A", and "From B" anyway.
I think this is deeper than just the VTable, and that it's more about the way it behaves in particular circumstances. Does B even have a VTable?
The call
func()
is equivalent to
this->func()
so there is a pointer involved.
Still, there's no need to involve pointers to understand the behavior.
Even a direct call of e.g. b.func() has to work as if it's a virtual call, when func is virtual in the statically known type. The compiler can optimize it based on knowing the most derived type of b. But that's a different kind of consideration (optimizations can do just about anything).
Apart from the issue of virtual dispatch, what may bring extra confusion, is that you have two mes, one declared in A and another declared in B. These are two distinct objects.
An object of type B has two data members of type std::string; one on its own, and one incorporated into the subobject of type A. The latter one, though, is not immediately available in the methods of type B because its name is eclipsed by the new me introduced in this class (though you may use a qualified name, A::me to refer to it).
Therefore, even though the bodies of A::func and B::func seem identical, the identifier me used in both of them refers to different members.
In your example, you won't see the difference:
With the virtual function, the compiler will generate a call via the VTable and at runtime, each objects will call the right function for their real class.
With the non virtual function, the compiler determines at compile time the right function to call, based on the objects defined class.
Now try the following, to see the virtual function in action:
A *pa = &b; // pointer to an A: valid as b is a B wich is also an A.
pa -> caller(); // guess what will be called if virtual or not.
No need for pointer to experimenting with virtual functions. You can observe the same effect with references as well:
A& ra = b; // create a reference to an A, but could as well be a parameter passed by reference.
ra.caller();
Virtual functions are useful for polymorphism. The idea is that you work with a general object of a class, but you don't know at compile time, if at runtime the object will really be of this class, or if it will not be a more specialiszed object (inheriting from the class).
In this thread the author of the accepted answer explains why the overridden method in the derived class can not be resolved by the compiler. However the example is relative to a type cast resolution, that is both the base and derived overloaded method have one parameter only and the ambiguity is limited to that parameter type.
But where is the ambiguity when the overloaded methods have a different number of parameters, like in this example?
Note that I'm not asking why the example produces a compile error, I'm asking why the language was designed this way.
#include <iostream>
using namespace std;
class A
{
public:
inline int f(int x) { return x; }
};
class B: public A
{
public:
inline int f(int x, int y) { return x+y; }
};
int main()
{
B b;
cout << b.f(1) << endl; // COMPILE ERROR
cout << b.f(1,2) << endl;
}
The reason you get a compiler error is that f from class A is hidden by the f in class B.
When the compiler does member name lookup, it uses base classes only if the name is not found in the object's class, so it doesn't matter if you have a member in a base class that has a proper parameter list for your call.
From the standard:
10.2.5 Otherwise (i.e., C does not contain a declaration of f or the resulting declaration set is empty), S(f, C) is
initially empty. If C has base classes, calculate the lookup set for f in each direct base class subobject Bi
,
and merge each such lookup set S(f, Bi) in turn into S(f, C).
In C++, name lookup will stop looking for other names as soon as it find the requested name in one of the base classes.
In your case, the name f is defined in B, so the compiler stop looking in the other base classes.
You can make A::f visible with a using declaration :
class B: public A
{
public:
using A::f;
int f(int x, int y) { return x+y; }
};
The compiler will look for the implementation of function f in class B. The compiler found such an implementation, which has two arguments. You provided only one argument, so there is your error.
How would you take away overloads that make no sense in a derived class? Even in your example, assume that if you have a B instance, you wanted to forbid the use of the single-parameter function. As it is written now, you've removed the single-parameter version (well, at least removed it from name resolution in the context of a B instance). But if you wanted to still have that version available, you can specify using A::F; in your class to bring in the single-parameter version.
I was going through this Book and I can't wrap my head around this:
if B::f(int) hides A::f(), why does pa1->f(); not give an error?
Doesn't name hiding mean that, the function f() doesn't exist in class B? And if pa1 points to an object of class B then pa1->f(); should result in an error just as b.f() does!
Please explain this, as I can't understand it through the book!
Thanks in advance!
#include <iostream>
using namespace std;
struct A {
virtual void f() { cout << "Class A" << endl; }
};
struct B: A {
void f(int) { cout << "Class B" << endl; }
};
struct C: B {
void f() { cout << "Class C" << endl; }
};
int main() {
B b; C c;
A* pa1 = &b;
A* pa2 = &c;
// b.f();
pa1->f();
pa2->f();
}
It would be an error if you tried to call f() from scope of B. But, you're calling it through a pointer to base class. The name lookup and overload resolution is done based on the static type of the object, A* in this case. From there, f() is visible.
if B::f(int) hides A::f(), why does pa1->f(); not give an error?
Because pa1 points to A, and A has a member called f which can be called like that. In this context, any other class (including B) is irrelevant.
Doesn't name hiding mean that, the function f() doesn't exist in class B?
No. It means that, in the context of B, the only function called f that can be found by unqualified lookup is B::f. It doesn't remove f from any other context, or prevent it from being found by qualified lookup such as b.A::f().
And if pa1 points to an object of class B then pa1->f(); should result in an error just as b.f() does!
The dynamic type is B, so that's the type used (at run time) to call virtual functions. Non-virtual functions are selected by the compiler according to the static type, which is A. In general, the compiler doesn't know the dynamic type; all it knows is that the pointer points to an A or some unknown derived class.
The call pa1->f(); is first routed to object of type A, since pa1 is a pointer to that type. The virtual keyword would re-route the call to type B if there was a function that matches the exact(!!) signature of the call. Since there is no such function in type B, the type A function is executed.
What I mean is that in this case the functions do not "hide" each other because the signature differs. [f(void) vs. f(int)]
EDIT:
To be more clear. f(int) and f(void) are two completely different functions. As different as f(void) to g(int) would be.
struct A{
virtual void fun(){cout<<"A";}
};
struct B:public A{
void fun(){cout<<"B";}
};
struct C:public B{
void fun(){cout<<"C";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
return 0;
}
In the above code B::fun() is getting converted to virtual function implicitly as I have made A::fun() virtual. Can I stop this conversion?
If not possible what are the alternatives to make the above code print "BB" ?
A virtual function is virtual in all derived classes. There is no way to prevent this.
(§10.3/2 C++11) If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf. For convenience we say that any virtual function overrides itself.
However, if you'd like to use the function that corresponds to the static, rather than the dynamic, type of a pointer (i.e., in your example, B::fun instead of C::fun, given that the pointer is declared as B*), then you can, at least in C++11, use the alias definition below to get access to the static (=compile-time) type:
template <typename Ptr>
using static_type = typename std::remove_pointer<Ptr>::type;
This is how you'd use this in main() (or anywhere else):
int main()
{
C c; B b1;
A *a = &b1;
a->fun();
B *b = &c;
/* This will output 'B': */
b->static_type<decltype(b)>::fun();
return 0;
}
If you do not want your derived classes to override the function then there is no reason why you should mark it virtual in base class. The very basis of marking a function virtual is to have polymorphic behavior through derived class function overidding.
Good Read:
When to mark a function in C++ as a virtual?
If you want your code to guard you against accidental overidding in derived classes.You can use the final specifier in C++11.
Yes, if you want to explicitly call a function in a specific class you can use a fully qualified name.
b->A::fun();
This will call the version of fun() belonging to A.
The following achieves the observable behaviour you're asking for. In A, non-virtual fun() run virtual fun_() so the behaviour can be customised in B, but anyone calling fun() on a derived class will only see the non-polymorphic version.
#include <iostream>
using namespace std;
struct A{
void fun(){fun_();}
private:
virtual void fun_() { cout << "A\n"; }
};
struct B:public A{
void fun(){cout<<"B\n";}
private:
virtual void fun_() final { fun(); }
};
struct C:public B{
void fun(){cout<<"C\n";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
c.fun(); // notice that this outputs "C" which I think is what you want
}
If using C++03, you can simply leave out the "final" keyword - it's only there to guard against further unwanted overrides of the virtual behaviour in B-derived classes such as C.
(You might find it interesting to contrast this with the "Nonvirtual Interface pattern" - see C++ Coding Standards by Sutter and Alexandrescu, point 39)
Discussion
A having fun virtual implies that overriding it in derived classes is a necessary customisation ability for derived classes, but at some point in the derivation hierarchy the choice of implementation behaviours might have narrowed down to 1 and providing a final implementation's not unreasonable.
My real concern is that you hide A/B's fun() with C::fun... that's troubling as if they do different things then your code could be very hard to reason about or debug. B's decision to finalise the virtual function implies certainty that there's no need for such further customisation. Code working from A*/A&/B*/B& will do one thing, while wherever a C object's type is statically known, the behaviour may differ. Templated code is one place where C::fun may easily be called without the template author or user being very conscious of it. To assess whether this is a genuine hazard for you, it would help to know what the functional purpose of "fun" is and how implementation might differ between A, B and C....
If you declare the function in B like this
void fun(int ignored=0);
it will become an overload which will not take part in resolving virtual calls. Beware that calling a->fun() will call A::fun() though even if a actually refers to a B, so I would strongly advise against this approach as it makes things even more confusing than necessary.
Question is: What exactly is it that you want to achieve or avoid? Knowing that, people here could suggest a better approach.
I have the following classes:
class A {
public:
virtual void f() {}
};
class B : public A{
public:
void f(int x) {}
};
If I say
B *b = new B();
b->f();
the compiler says error C2660: 'B::f' : function does not take 0 arguments.
Shouldn't the function in B overload it, since it is a virtual function? Do virtual functions get hidden like this?
EDIT: I indeed meant to inherit B from A, which shows the same behaviour.
Assuming you intended B to derive from A:
f(int) and f() are different signatures, hence different functions.
You can override a virtual function with a function that has a compatible signature, which means either an identical signature, or one in which the return type is "more specific" (this is covariance).
Otherwise, your derived class function hides the virtual function, just like any other case where a derived class declares functions with the same name as base class functions. You can put using A::f; in class B to unhide the name
Alternatively you can call it as (static_cast<A*>(b))->f();, or as b->A::f();. The difference is that if B actually does override f(), then the former calls the override, whereas the latter calls the function in A regardless.
Class B does not derive from A so no function F() exists. You probably meant:
class A {
public:
virtual void f() {}
};
class B : public A {
public:
void f(int x) {}
};
Edit: I missed the actual function hiding. See Steve Jessop answer for more thorough explanation.
No, and yes, respectively. If you want the overloading behaviour, you need to say
using A::f;
in B.
B does not derive from A, the correct declaration is:
class B : public A
When the compiler has more than one way to resolve a symbol, it has to choose which one has precedence unless the code tells it otherwise. What you are expecting is the overloading to take precedence over the overriding. (over, over, over, aaaaack! Sorry, got 'over'whelmed).
This example has B inheriting a virtual method in which the subclass provides an overloaded version. Overloads are for methods in the same class using the same method name but different signatures. Since B is a subclass of A, it is overriding f(), which means it cannot also be an overload at the same time. This is why it is being hidden.
For class A, declaring method
virtual void f() {}
as virtual means that method will be resolved using a certain set of rules that are not consistent with your declaration of b.
B *b = new B();
By creating 'b' as an instance of "B", the compiler has no need to use the virtual nature of the method of the same name in "A".
If you had declared 'b' like this
B *b = new A();
then the call b->f(); would indeed refer to the method in A by making use of the virtual resolution.
It seems that it is exist rather similar question with answer in Biern Stroustrup's FAQ: http://www.stroustrup.com/bs_faq2.html#overloadderived
As he said:
"In C++, there is no overloading across scopes"
but if you want
"That's easily done using a using-declaration"