Inheritance of operator() - c++

I am stumped by why the declaration of void operator()(int) in the base class in the code sample below is seemingly hidden when the derived class implements void operator()(int,int,int). How can I get the declaration of operator()(int) from the base class foo to be visible in the derived class bar? That is, how can I modify the example so that the invocation of operator()(int) works?
#include <iostream>
struct foo
{
void operator()(int)
{
std::cout << "A" << std::endl;
}
};
struct bar : foo
{
// If this is uncommented, the code will not compile.
// void operator()(int, int, int) {}
};
int main()
{
bar b;
b(1);
return 0;
}
When compiled with g++ with the marked lines uncommented, the error message is along the lines of "no match for call to 'bar (int)' ... candidate is void bar::operator()(int,int,int) ... candidate expects 3 arguments, 1 provided."

That's right. Derived class functions hide base class functions rather than overloading. The fix is pretty simple though:
struct bar : foo
{
using foo::operator();
void operator()(int, int, int) {}
};

Note that operator() might make this look more confusing than it is. The classic example would probably be something more like bar::mymethod(int) and foo::mymethod(). The derived method hides the inherited method because of how resolution happens. The using declaration explained in another answer brings in foo's method for resolution.

Related

Using std::function with inherited classes

I've had a little issue with some functional callbacks. How does one define a function so that I can have an f of derived x, and assign it to a derived, but given the function object wants the base class.
Can this be done? It makes sense logically. Perhaps I'm missing some form of pointer usage?
This is a simplified form of the actual software I'm working as a base reproducible.
#include <functional>
#include <iostream>
class base {
public:
std::function<void(base*)> foo;
};
class derived : public base {
public:
//EDIT:Would this work?
std::function<void(derived*)> foo;
int bar = 0;
};
void f(derived* x)
{
x->bar++;
}
int main()
{
derived d;
d.foo = f; //Issue no matching operator, LHS std::function<void(base)> , RHS void(derived)
d.foo(&d); //No match for call to std::function<void(base)>
std::cout << d.bar;
}
EDIT: fixed the invocation because silly mistake, also tweaked it slightly on what may work?
I'm not sure I understand fully what you want, but the call
d.foo();
doesn't work because it takes an argument of type base.You can work around that by defining foo to not take an argument.
class base {
public:
std::function<void(void)> foo;
};
The call in main then has to be rewritten as
int main()
{
derived d;
d.foo = [&d]{ f(d); };
...
}
which works, but may not be what you intended. See live example here;

Derived class calling parent class's method that calls an overriden virtual method calls the wrong method

First of all, sorry for the confusing title. I have no idea how to word this properly.
The problem is not really a problem, but rather something that I don't know how to implement.
Here is the code:
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
void foo()
{
std::cout << "Child's foo" << std::endl;
}
};
int main()
{
Child c;
c.bar();
return 0;
}
When the code above runs, it prints outChild's foo.
However the same code, BUT with the child classes foo definition beingvoid foo(bool def = true)Prints out Parent's foo.
Is there anyway to call the child's version of foo instead of the parent's one if the definitions missmatch?
Unfortunately not, if you want to add extra parameters, even default ones, you can create an overloaded function explicitly, which behaves similar in most cases to the caller.
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
virtual void foo(bool def) // virtual if another subclass needs to override
{
std::cout << "Child's foo def = " << def << std::endl;
}
virtual void foo()override //override and virtual optional here
{
foo(true);
}
};
int main()
{
Child c;
c.bar();
c.foo();
c.foo(true);
return 0;
}
This is purely a function of when a function is overridden in C++.
In C++, function overriding is done according to the "signature" of member functions:
unqualified name
exact parameters list in the declaration (excluding implicit this)
qualification of the this implicit parameter
Obviously, by definition, the type of the this parameter cannot match exactly, as by definition the type must be a pointer to a derived class.
[Note about cv-qualification on parameters:
The parameters in the declaration as seen by caller must be exactly the same, that is after removal of meaningless cv-qualifiers on object copies: these are cv-qualifiers on local variables inside the function body, and that's only meaningful in a function definition.
void f(const int i); // takes an int by value; const is meaningless
void f(int i); // redeclaration of the same function
// redeclaration of the same function yet again
void f(const int ci) { // const is meaningful here
ci = 1; // error
}
--end note]
However the same code, BUT with the child classes foo definition
being void foo(bool def = true) Prints out Parent's foo.
Because there is no match of the parameters lists: an empty parameter list is only matched by an empty parameter list.
You need to replace the default argument with two overloaded functions here, with no forwarding to the other:
void foo(bool def); // new function signature
void foo() { // overrides Parent's member
foo(true);
}
With long complex a parameters list, it's easy to change a type and create a new function signature instead of overriding a base class virtual function; it's also easy to get the capitalisation wrong or spelling wrong (think English vs. US spelling). In general, getting the name of a function wrong (or any other name: of a type, of a template, of a variable...) causes a compilation error because that name with the small spelling change wasn't declared. But with a raw declaration of a member with the intent of overriding a base class declaration, there is no hint that you tried to do that and the compiler will not warn you (it might warn for hiding a base class declaration, but this is different). Explicitly marking a declaration intended to be an override with the virtual keyword doesn't help, introducing a new virtual function isn't the intent.
That was the sad state of affairs after the first version of the C++ standard was formalized. Now it's different.
If you want to be sure that you are indeed overriding a base class declaration, you can now use the override keyword:
class Child : public Parent
{
public:
void foo(bool def);
void foo() override {
foo(true);
}
};

Inheriting from a template class using the inheriting class

When I inherit from a class the compiler has to know the definition of the base class in order to create it. But when I inherit from a template class using oneself (the inheriting class), how can the compiler create the code? It does not know the size of the class yet.
#include <iostream>
template <class T> class IFoo
{
public:
virtual T addX(T foo, double val) = 0;
// T memberVar; // uncomment for error
};
class Foo : public IFoo<Foo>
{
public:
Foo(double value)
: m_value(value) {}
Foo addX(Foo foo, double b) override
{
return Foo(foo.m_value + b);
}
double m_value;
};
int main()
{
Foo foo1(1);
Foo foo2 = foo1.addX(foo1, 1);
std::cout << foo2.m_value;
}
First I thought it works because it's an interface but it also works with a regular class.
When I store the template as a member i get an error that Foo is undefined, just as I expected.
The general concept here is called the Curiously Recurring Template Pattern or CRTP. Searching on that will get lots of hits. see: https://stackoverflow.com/questions/tagged/crtp .
However there is a simple explanation that likely answers your question without getting too much into CRTP. The following is allowed in C and C++:
struct foo {
struct foo *next;
...
};
or with two types:
struct foo;
struct bar;
struct foo {
struct bar *first;
...
};
struct bar {
struct foo *second;
...
};
So long as only a pointer to a struct or class is used, a complete definition of the type doesn't have to be available. One can layer templates on top of this in a wide variety of ways and one must be clear to reason separately about the type parameterizing the template and its use within the template. Adding in SFINAE (Substitution Failure Is Not An Error), one can even make templates that do no get instantiated because things cannot be done with a given type.
With this definition of template class IFoo, the compiler does not need to know the size of Foo to lay out IFoo<Foo>.
Foo will be an incomplete class in this context (not "undefined" or "undeclared") and usable in ways that any incomplete type can be used. Appearing in a member function parameter list is fine. Declaring a member variable as Foo* is fine. Declaring a member variable as Foo is forbidden (complete type required).
how can the compiler create the code?
Answering this question would be the same as answering this question: How can the compiler compile that?
struct Type;
Type func(Type);
Live example
How can you define a type that doesn't exist and yet declare a function that use that type?
The answer is simple: There is no code to compile with that actually use that non-existing type. Since there is no code to compile, how can it even fail?
Now maybe you're wondering what is has to do with your code? How does it make that a class can send itself as template parameter to it's parent?
Let's analyze what the compiler see when you're doing that:
struct Foo : IFoo<Foo> { /* ... */ };
First, the compile sees this:
struct Foo ...
The compiler now knows that Foo exists, yet it's an incomplete type.
Now, he sees that:
... : IFoo<Foo> ...
It knows what IFoo is, and it knows that Foo is a type. The compiler now only have to instanciate IFoo with that type:
template <class T> struct IFoo
{
virtual T addX(T foo, double val) = 0;
};
So really, it declares a class, with the declaration of a function in it. You saw above that declaring a function with an incomplete type works. The same happens here. At that point, Your code is possible as this code is:
struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
So really there's no sorcery there.
Now let's have a more convincing example. What about that?
template<typename T>
struct IFoo {
void stuff(T f) {
f.something();
}
};
struct Foo : IFoo<Foo> {
void something() {}
};
How can the compiler call something on an incomplete type?
The thing is: it don't. Foo is complete when we use something. This is because template function are instantiated only when they are used.
Remember we can separate functions definition even with template?
template<typename T>
struct IFoo {
void stuff(T f);
};
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
struct Foo : IFoo<Foo> {
void something() {}
};
Great! Does it start looking exactly the same as your example with the pure virtual function? Let's make another valid transformation:
template<typename T>
struct IFoo {
void stuff(T f);
};
struct Foo : IFoo<Foo> {
void something() {}
};
// Later...
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
Done! We defined the function later, after Foo is complete. And this is exaclty what happens: The compiler will instanciate IFoo<Foo>::stuff only when used. And the point where it's used, Foo is complete. No magic there either.
Why can't you declare a T member variable inside IFoo then?
Simple, for the same reason why this code won't compile:
struct Bar;
Bar myBar;
It doesn't make sense declaring a variable of an incomplete type.

"Ambiguous call to overloaded function"

I have a structure like this, with struct Baz inheriting from 2 different structs, Foo and Bar.
I have 2 methods called the same thing, one with a parameter of Foo and one with a parameter of Baz.
struct Foo
{
};
struct Bar
{
};
struct Baz : Foo, Bar
{
virtual void something(const Foo& foo)
{
};
virtual void something(const Bar& bar)
{
};
};
I call it like this
Baz baz;
baz.something(baz);
And understandably I have an issue with my code knowing which function I am calling if I pass it an instance of Baz. I get “Ambiguous call to overloaded function”.
I know I can cast my Baz to Foo or Bar to resolve the issue...
Baz baz;
baz.something((Bar)baz);
...but is there another way of dealing with this design issue?
I want to call the Foo method ONLY if the object being passed is not of type Bar.
edit:
If this was C# (which it isn't) I could probably solve this using a template where clause.
First off, note that the cast you've used would create a temporary object. You probably meant this:
baz.something(static_cast<Bar&>(baz));
And to answer your question, it should be possible to use SFINAE for this:
struct Baz : Foo, Bar
{
virtual void something(const Bar &bar)
{ /* ... */ }
template <
class T,
class = typename std::enable_if<
std::is_convertible<const T&, const Foo&>::value &&
!std::is_convertible<const T&, const Bar&>::value
>::type
>
void something (const T &foo)
{ something_impl(static_cast<const Foo&>(foo)); }
private:
virtual void something_impl(const Foo &foo)
{ /* ... */ }
};
Live example

C++ member function virtual override and overload at the same time

If I have a code like this:
struct A {
virtual void f(int) {}
virtual void f(void*) {}
};
struct B : public A {
void f(int) {}
};
struct C : public B {
void f(void*) {}
};
int main() {
C c;
c.f(1);
return 0;
}
I get an error that says that I am trying to do an invalid conversion from int to void*. Why can't compiler figure out that he has to call B::f, since both functions are declared as virtual?
After reading jalf's answer I went and reduced it even further. This one does not work as well. Not very intuitive.
struct A {
virtual void f(int) {}
};
struct B : public A {
void f(void*) {}
};
int main() {
B b;
b.f(1);
return 0;
}
The short answer is "because that's how overload resolution works in C++".
The compiler searches for functions F inside the C class, and if it finds any, it stops the search, and tries to pick a candidate among those. It only looks inside base classes if no matching functions were found in the derived class.
However, you can explicitly introduce the base class functions into the derived class' namespace:
struct C : public B {
void f(void*) {}
using B::f; // Add B's f function to C's namespace, allowing it to participate in overload resolution
};
Or you could do this:
void main()
{
A *a = new C();
a->f(1); //This will call f(int) from B(Polymorphism)
}
Well I think first of all you did not understand what virtual mechanism or polymorhism. When the polymorphism is achieved only by using object pointers. I think you are new to c++. Without using object pointers then there is no meaning of polymorphism or virtual keyword use base class pointer and assign the desired derived class objects to it. Then call and try it.