reimplementing an interface in a derived class

Simen Kjærås simen.kjaras at gmail.com
Fri Jan 4 09:19:48 UTC 2019


On Friday, 4 January 2019 at 08:40:04 UTC, Alex wrote:
> class A
> {
> public:
>     int foo(){return 1;}
> };
> class B : public A
> {
> public:
>     int foo(){return 2;}
> };

In C++, methods are non-virtual by default. In D, they are 
virtual by default. Because of this, the two examples are 
different. In fact, D disallows overriding non-virtual, 
non-private functions, as specified in 
https://dlang.org/spec/function.html#virtual-functions. For 
private functions it does work, though:

class A {
     private final int foo() { return 1; }
}
class B : A {
     final int foo() { return 2; }
}

unittest {
     assert((new A).foo == 1);
     assert((new B).foo == 2);
     assert((cast(A)(new B)).foo == 1);
}

> Now I have the feeling, I'm missing something elementary... 
> sorry for this...
> But take the classic example of OOP of an Animal and a Dog: 
> Animal.
> Let the animal implement some default move and eat behavior.
> Let the dog override the move method and implement bark.
> If you degrade the dog to the animal by casting it should still 
> be able to move and eat, but not bark.


Imagine you give me a box with an Animal in it. You know it's a 
Bird, but I only know it's an Animal of some kind.

Case 1: I tell it to move() to the top of a tree. Would you 
expect it to climb or fly?
(let's not get into penguins and other flightless birds right 
now, the OOP animal metaphor is strained enough as it is)

Case 2: I try to tell it to bark(), but there's no way to do 
that, because I have access to it as an Animal, not a Dog.
Cutting off its beak and gluing a muzzle there (casting a Bird to 
a Dog) will only lead to suffering.

Case 1 is overriding - Bird has defined how move() should work, 
and it will do that even if you only know it's an animal of some 
kind. Case 2 is subclassing - a Dog can do things that the 
average Animal can't, and this is reflected in it having a wider 
interface - more methods.

This can be exemplified in D as:

import std.stdio : writeln;

abstract class Animal {
     abstract void move();
}

class Bird : Animal {
     override void move() {
         writeln("Flying.");
     }
}

class Dog : Animal {
     override void move() {
         writeln("Walking."); // Assume this is not Muttley
     }
     void bark() {
         writeln("Woof!");
     }
}

unittest {
     (new Bird).move(); // Flying
     (cast(Animal)new Bird).move(); // Flying
     //(cast(Animal)new Bird).bark(); // Fails to compile - 
generic animals can't bark
     (cast(Dog)new Bird).bark(); // Crashes because a Bird is not 
a Dog, cast returns null.
}

--
   Simen


More information about the Digitalmars-d-learn mailing list