0

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?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Rokas Višinskas
  • 533
  • 4
  • 12
  • 1
    No this is not possible if the definitions mismatch. – pschill Sep 28 '18 at 15:04
  • Since the Child is changing the signature of foo, you could also consider making a different function name. Why? Because foo is the API of the parent, and when a Child is used for where Parent is allowed those places will use the Parent's public API. Having Child's foo with a different signature confuses the two things, making it harder to reuse (i.e., polymorphism) Child as a Parent for code expecting a Parent. – Eljay Sep 28 '18 at 15:33

2 Answers2

2

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;
}
Fire Lancer
  • 29,364
  • 31
  • 116
  • 182
  • I wouldn't add `virtual` to `foo(bool)` by default. If I have to add a `virtual`, it would be for `Parent` destructor. – Jarod42 Sep 28 '18 at 15:42
1

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);
    }
};
curiousguy
  • 8,038
  • 2
  • 40
  • 58