Calling overloaded parent methods from child class in D

62 Views Asked by At

Suppose I have the following D code:

class Parent {
    void print(int x) {
        import std.stdio : writeln;
        writeln(x);
    }

    abstract void print(string s);
}

class Child : Parent {
    override void print(string s) {
        import std.stdio : writeln;
        writeln(s);
    }
}

unittest {
    Child c = new Child();
    c.print(5);
}

When I compile this code, I get a compiler error stating that

function Child.print(string s) is not callable using argument types (int)

This is confusing, because I would expect that the parent's print(int x) method would be invoked when calling it on the child. I can solve this casting inline, like (cast(Parent)c).print(5), but this seems awkward.

Is this a bug in the language? Or is there a better approach to inheritance with overloaded methods?

2

There are 2 best solutions below

0
Michael Parker On BEST ANSWER

You'll need to modify Child with an alias to Parent.print:

class Child : Parent {
  
    alias print = Parent.print;

    override void print(string s) {
        import std.stdio : writeln;
        writeln(s);
    }
}

This is intentional. It's to prevent function hijacking. You can read about it here: https://dlang.org/articles/hijack.html

The relevant text from the section 'Derived Class Member Function Hijacking':

C++ has the right idea here in that functions in a derived class hide all the functions of the same name in a base class, even if the functions in the base class might be a better match. D follows this rule. And once again, if the user desires them to be overloaded against each other, this can be accomplished in C++ with a using declaration, and in D with an analogous alias declaration.

0
DejanLekic On

"Problem" is in the overloading...

The following code will work because it avoids overloading of the "print" method:

class Parent {
    void printInt(int x) {
        import std.stdio : writeln;
        writeln(x);
    }

    abstract void printString(string s);
}

class Child : Parent {   
    override void printString(string s) {
        import std.stdio : writeln;
        writeln(s);
    }
}

void main() {
    Child c = new Child();
    c.printInt(5);
}

If you really do want to overload the print() method, then you should have something like override void print(int x) { super.print(x); } in your Child:

class Parent {
    void print(int x) {
        import std.stdio : writeln;
        writeln(x);
    }

    abstract void print(string s);
}

class Child : Parent {
    override void print(int x) { super.print(x); }

    override void print(string s) {
        import std.stdio : writeln;
        writeln(s);
    }
}

void main() {
    Child c = new Child();
    c.print(5);
}