D does not have multiple inheritance like C++. Instead, it follows a Java-style pattern of one base class, multiple interfaces. However, using mixin templates, we can simulate all aspects of multiple inheritance.
We need to execute the following steps to simulate multiple inheritance with mixin templates:
class
body.The code is as follows:
import std.stdio : writeln; interface Base1 { void foo(); } mixin template Base1_Impl() { void foo() { writeln("default foo impl"); } } interface Base2 { void bar(); void baz(); } mixin template Base2_Impl() { int member; void bar() { writeln("default bar impl"); } void baz() { writeln("default bazimpl"); } } classMyObject : Base1, Base2 { mixin Base1_Impl!(); mixin Base2_Impl!(); void baz() { writeln("custom bazimpl"); } } void main() { MyObjectobj = new MyObject(); Base1 base1 = obj; // works on all interfaces Base2 base2 = obj; // works on all interfaces obj.foo(); // call methods through object obj.baz(); // note that the custom one is called base2.bar(); // or through interface base2.baz(); }
On running the preceding program, we will get the following output:
default foo impl custombazimpl default bar impl custombazimpl
Inheriting and implementing multiple interfaces will allow your object to implicitly convert to the various interface types. The problem is they cannot have default virtual implementations. That's where the mixin template comes in.
A mixin template
(not to be confused with the mixins
string we used before) is a parameterized list of declarations which is inserted into the mixin
site, almost as if you copied and pasted the code and compiled it.
Here, we paired a mixin template
with each interface, putting the interface implementation in the template. An interesting feature of these templates is that they will not conflict with names written in the object. As a result, we can selectively override functions from the mixin template
, as we did with the custom baz
implementation.
When customizing functions, you may also wish to call the default implementation. To do this, give the mixin template
a name and then refer to it by that name:
mixin Base2_Impl!() b2; // name it void baz() { writeln("custom bazimpl"); b2.baz(); // refer to the function by full name }
The other functions will still appear in the object—you will not have to refer to them by the full b2.bar
name. The name is only used when disambiguating.
18.224.59.145