Overloading rules for inheritance in C++ - c++

The following does not compile (Apple LLVM version 4.2 (clang-425.0.28)):
class A {
public:
virtual void foo() {};
virtual void foo( int i ) {};
};
class B : public A {
public:
virtual void foo( int i ) override { foo(); }
};
The compiler error is "Too few arguments" for the call to foo() inside B::foo(int). The compiler apparently thinks that I want to recursively call B::foo(int) and does not recognize that I want to call A::foo(void).
The error goes away if I replace the call to foo() by A::foo().
But:
1) Why is this happening? It seems obvious to just resolve to A::foo() in this case (or an overridden function down the class hierarchy).
2) More importantly, if I want to use polymorphic late binding for foo(void) as well, specifying A::foo() is not what I want, B::foo() of course produces a compiler error as well.
Thanks in advance for any enlightenment!

A name in a derived class hides the same name in base classes. In other words, when resolving foo in the context of B, name lookup finds B::foo and stops there. A::foo is never found.
Add using A::foo; within B's definition.

Related

Difference between redefining and overriding a function

Suppose I have class A with a virtual function F():
class A
{
virtual void F()
{
// Do something
};
};
And I have another class B which inherits A and redefines F():
class B : A
{
void F()
{
// Do something
};
};
And a different class C which also inherits A but overrides F():
class C : A
{
void F() override
{
// Do something
};
};
What is the difference between F() in classes B and C?
Both are overrides.
When you use the keyword override you ensure a compilation failure if it should happen to not be an override.
And that's good practice.
Both B::f() and C::f() are overrides and they are exactly the same.
override is essentially a compile-time advisory term that will cause a compilation error if the function does not override one in a base class.
This can help program stability: if the name and parameter types to A::f() are changed, then a compile error will result.

non virtual method call in a virtual method, C++

Here is the code I'm talking about
#include <stdio.h>
#include <stdlib.h>
class A {
public:
void method() {printf("method A\n");}
virtual void parentMethod() { printf("parentMethod\n"); method(); }
};
class B : public A {
public:
void method() {printf("method B\n");}
};
int main(void) {
A a;
B b;
a.parentMethod();
b.parentMethod();
}
My question is why this is happening? Why when b.parentMethod() is called it doesn't print method B. I realize that it has something to do with method() being in A and B as well as being non-virtual, but I can't get my head around it. Would someone be able to explain this behaviour?
Any help is appreciated.
You code was missing a virtual keyword:
#include <stdio.h>
#include <stdlib.h>
class A {
public:
virtual void method() {printf("method A\n");} // virtual was missing
void parentMethod() { printf("parentMethod\n"); method(); } // unnecessary virtual keyword
};
class B : public A {
public:
void method() {printf("method B\n");}
};
int main(void) {
A a;
B b;
a.parentMethod();
b.parentMethod();
}
The definition in the most upper class must contain the virtual keyword. It is very logical if you think about it. In this case, when you call method() the compiler knows it has to do something more than with a normal function call immediately.
Otherwise, it would have to find and iterate on all the derived types to see if they contain a redefinition of method().
My question is why this is happening? Why when b.parentMethod() is called it doesn't print method B. I realize that it has something to
do with method() being in A and B as well as being non-virtual, but I
can't get my head around it. Would someone be able to explain this
behaviour?
C++ has two levels of indirection when it comes to classes/structures. You have your "plain functions" (including "overloaded", "lambdas", static, etc.) and you have your "virtual functions". First, let's explain "plain functions".
struct Foo {
void goo();
};
In this structure, goo is just a plain old functions. If you try to write it in C, this would be analogous to calling,
void goo(struct Foo *this);
Nothing magical, just a plain function with a "hidden" pointer (all c++ functions have that "hidden" this pointer passed to them). Now, let's re-implement this function in an inherited structure,
struct Goo : public Foo {
void goo();
};
...
Goo g;
g.goo();
Foo f;
f.goo();
Here, plain as day, g.goo() calls goo() in Goo structure, and f.goo() calls goo() in Foo structure. So, in C functions, this would be just,
void goo(struct Foo *this);
void goo(struct Goo *this);
provided C did parameter overloading. But still, just plain functions. Calling goo() in Foo object will call different function than calling goo() in Goo object. Compile time resolution only. But now, let's make our function "virtual"
struct Foo {
virtual void goo();
};
struct Goo : public Foo {
void goo(); // <- also virtual because Foo::goo() is virtual
// In C++11 you'll want to write
// void goo() override;
// which verifies that you spelled function name correctly
// and are not making *new* virtual functions! common error!!
};
...
Goo g;
g.goo();
Foo f;
f.goo();
What happens here is that Foo now contains a "virtual table". The compiler now creates a table of functions that maps location of "latest" goo() function. Namely, implicit Foo() constructor would do something like,
virt_table[goo_function_idx] = &Foo::goo;
and then the constructor in Goo() would update this table with,
virt_table[goo_function_idx] = &Goo::goo;
And then when you have,
Foo *f = new Goo();
f->goo();
what happens is akin to,
f->virt_table[goo_function_idx]();
The function location is looked up in the "virtual table", and that function is called. This means runtime resolution of functions, or polymorphism. And this is how Goo::goo() is called.
Without this table, the compiler can only call functions it knows for said object. So in your example, b.parentMethod() is looked up in the table and called. But method() is not part of that table, so only compile-time resolution is attempted. And since this pointer is A*, you get A::method called.
I hope this clears up the "virtual table" business - it's literally an internal lookup table, but only for functions marked as virtual!
PS. You may ask, "but the this pointer will get 'upcast' by the virtual table from Foo* to Goo*", and yes, it would. I'll leave it as an exercise for you to figure out why that would always be correct.
Well you are correct. This is happening because your method is not virtual. When you are calling it through the parent class, there is no way for it to know, that it was overloaded, so A::method is always called. If you mark method as virtual, then call to it will be routed through the class vtable, so A::method would be replaced by the B::method in the ascendant class.
virtual means that a method can be overridden in a subclass. I think you wanted method, not parentMethod, to be overridden for B. I've renamed parentMethod to foo to be less misleading.
#include <stdio.h>
#include <stdlib.h>
class A {
public:
virtual void method() {printf("method A\n");}
void foo() { printf("foo\n"); method(); }
};
class B : public A {
public:
void method() {printf("method B\n");}
};
int main(void) {
A a;
B b;
a.foo();
b.foo();
}
You'll see that this gives the expected output:
foo
method A
foo
method B
Here's the ideone.

Virtual functions and default parameters

Lets say I have a class A, B and C
class A{
public:
virtual void f4(){
cerr<<"A::f4()"<<endl;
}
};
class B: public A{
public:
virtual void f4(int n){
cerr<<"B::f4("<<n<<")"<<endl;
}
};
class C: public B{
public:
virtual void f4(int n = 1){
cerr<<"C::f4("<<n<<")"<<endl;
}
};
If I have:
C c;
A& rac = c;
rac.f4();
I was expecting c's version of f4 to be called but that's not what happens. Can someone explain?
Compiling with clang -Wall the following warnings occur:
main.cpp:14:22: warning: 'B::f4' hides overloaded virtual function [-Woverloaded-virtual]
virtual void f4(int n){
^
main.cpp:6:22: note: hidden overloaded virtual function 'A::f4' declared here: different number of parameters (0 vs 1)
virtual void f4(){
^
These warnings explain what's going on. A virtual function is only overridden by another function with the same signature.
B::f4(int) does not override A::f4() because they have different parameter lists. Instead, it is a different virtual function.
So rac.f4() just calls A::f4() which is not overridden.
Since C++11 you can help to detect this problem:
virtual void f4(int n) override {
// ^^^^^^^^
Then the compiler will give an error if this function does not actually override something from the base.
Because the signatures of f4 don't match between A and B/C classes.
This is A's function signature for f4:
void A::f4() // no parameters
B and C use this function signature
void B::f4(int n)
If you are doing to override a method, it needs to have the same return type and identical parameter list. Otherwise, even if the method in the derived class has the same name as the parent class, C++ will don't consider that an override.
FWIW, C::f4 does override B::f4. The default parameter you introduce on class C doesn't influence the virtual methods override behavior. And this is the exact reason why, on my team, we disallow overloading methods with different signatures and banning default parameters. Because it leads to bugs like this.
Here's C's v-table (the methods available on it):
void C::f4(); // no parameters, overrides A::f4()
void C::f4(int n); // overrides B::f4()

abstract base class calling parent's pure virtual function [duplicate]

This question already has answers here:
Derived template-class access to base-class member-data
(3 answers)
Closed 8 years ago.
A coworker asked me today about code which looks somewhat like this:
#include <iostream>
template <class T>
class IBase {
public:
virtual ~IBase() {}
public:
virtual void foo() = 0;
};
template <class T>
class Base : public IBase<T> {
public:
virtual void bar() {
foo(); // compiler error
}
};
class Derived : public Base<int> {
public:
virtual void foo() {
std::cout << "Hello World!\n";
}
};
int main() {
Derived d;
d.bar();
}
At first he was getting a compiler error saying that "foo()" was not found. OK, so he tried to change it to IBase<T>::foo();. While that compiled, it resulting in a linker error. So immediately, I recalled that I've seen this type of problem before and suggesting that he write this->foo(); instead. Viola! problem solved!
Then he asked me why didn't plain foo(); work? Isn't this->x(); essentially the same as x();? Honestly, I have no idea, but he piqued my interest. So here we are:
In summary:
virtual void bar() {
this->foo(); // works
//IBase<T>::foo(); // linker error
//foo(); // compiler error
}
The question is why is this-> required. And why won't the other options work?
Because the base class member is a dependent name - its meaning depends on the template parameter, and so isn't known until the template is instantiated. The name isn't looked up in the generic IBase template, since that might be specialised to give it a different meaning before instantiation.
Qualifying it with IBase<T>:: calls the base-class function non-virtually; that's generally not what you want, especially if (as here) it's a pure virtual function with no implementation. Hence the linker error when you tried that.
Qualifying it with this-> tells the compiler that it's a member, and any further checking is deferred until the template is instantiated. The function is still called virtually.
Imagine you are the compiler. You have just been reading through and compiling the code and now you have reached the bar function. In this function, you see that there is an attempt to do foo(). At this point, do you know what foo is? You don't. It could come from the base class, but you can't possibly know, because you don't know what T is yet. It's certainly possible that there might be a specialization of IBase for which foo is something else entirely.
When you stick this-> before the function call, it causes the compiler to treat it as a dependent name. That means the compiler will say "Okay, this depends on the type of this, which I do not know yet. I'll wait until later, when I know how the class is being instantiated, before I look for foo."
IBase<T>::foo(); gives a linker error because there simply is no definition for foo in IBase<T>.
#include <iostream>
template <class T>
class IBase {
public:
virtual ~IBase() {}
public:
virtual void foo() = 0;
};
int foo() { std::cout << "hello!\n"; }
template <class T>
class Base : public IBase<T> {
public:
virtual void bar() {
foo(); // which foo?!
}
};
template <>
class IBase<int> {
public:
virtual ~IBase() {}
//virtual void foo() = 0; -- no foo()!
};
class Derived : public Base<int> {
public:
virtual void foo() {
std::cout << "Hello World!\n";
}
};
int main() {
Derived d;
d.bar();
}
The above illustrates why C++ does not allow members of dependent type parents to be implicitly found.
When you call foo() in Base, which foo() should be called? The one in IBase<T> or the free function foo()?
Either we put the decision off until later, or we go with the free function foo().
If we only go with the free function foo() if one is visible, then subtle changes in #include order can massively change what your program does. So if it should call the free function foo(), it must error if one is not found, or we are completely screwed.
If we defer the decision until later, it means less of the template can be parsed and understood until a later date. This moves more errors to the point of instantiation. It also results in some surprising behavior, like in the above case, where someone might think "I'm calling the method foo()", but actually ends up calling the free function foo() with no diagnostic.

Fixng unused formal parameter warnings without making an abstract class

I have a base class and it has virtual functions. The issue is that, the base is allowed to be instanced, but that means that all of its functions need a definition. This causes the compiler to warn me about unused parameters. What can I do to properly get rid of these warnings without making pure virtual functions and making it an abstract class?
example:
class Foo {
public:
virtual void bar(int x) {} //unused formal parameter int x
}
Thanks
Usual solution is:
virtual void bar(int x) { (void)x; }
or:
virtual void bar(int) {}
This prevents the compiler from whinging. Note that this technique isn't restricted to virtual member functions; it should work for any function where you don't intend to use one or more arguments.
On an unrelated note; an instantiable base class with empty member-function definitions doesn't sound like a very good idea; are you sure that you wouldn't be better off just making it abstract?
Is there a problem in using the absolutely most obvious solution?
class Foo {
public:
virtual void bar(int) {}
};
Just remove the parameter name.
For what it's worth, an alternative method is:
virtual void bar(int /*x*/) {}