Inheritance/Multiple: Difference between revisions
Content added Content deleted
(Expanded D entry to cover the multiple ways to do multiple inheritance.) |
|||
Line 119: | Line 119: | ||
=={{header|D}}== |
=={{header|D}}== |
||
D |
While D does not have multiple base class inheritance, you can inherit from multiple interfaces. |
||
<lang d>interface Camera { |
<lang d>interface Camera { |
||
Line 133: | Line 133: | ||
// MobilePhone, and CameraPhone |
// MobilePhone, and CameraPhone |
||
}</lang> |
}</lang> |
||
D also supports template mixins and alias this (multiple alias this are planned) |
|||
D also supports the [[non-virtual interface]] pattern, where an interface may have non-virtual methods with defined implementations. |
|||
that allows various forms of static composition. |
|||
<lang d>interface Camera { |
|||
// A virtual function. |
|||
Image takePhoto(); |
|||
// A non-virtual function. |
|||
final Image[] takeSeveralPhotos(int count) { |
|||
auto result = new Image[count]; |
|||
foreach (ref img; result) { |
|||
img = takePhoto(); |
|||
} |
|||
} |
|||
}</lang> |
|||
In addition, D's alias this feature allows one to create a type that, while it does not technically derive from two different classes, behaves as if it was. |
|||
<lang d>class A { |
|||
string foo() { |
|||
return "I am an A."; |
|||
} |
|||
} |
|||
class B { |
|||
string foo() { |
|||
return "I am a B."; |
|||
} |
|||
} |
|||
class C : A { |
|||
string className = "C"; |
|||
override string foo() { |
|||
return "I am a "~className~", and thus an A."; |
|||
} |
|||
@property |
|||
BWrapper asB() { |
|||
return new BWrapper(); |
|||
} |
|||
alias asB this; |
|||
class BWrapper : B { |
|||
override string foo() { |
|||
return "I am a "~className~", disguised as a B."; |
|||
} |
|||
} |
|||
} |
|||
unittest { |
|||
import std.stdio : writeln; |
|||
auto c = new C(); |
|||
A a = c; |
|||
B b = c; |
|||
writeln(a.foo()); |
|||
writeln(b.foo()); |
|||
}</lang> |
|||
You can currently only have a single alias this, but multiple alias this is planned. Nested alias this works today, but is somewhat finicky. |
|||
Lastly, D has template and string mixins. These can be used for static polymorphism, where a piece of code is written once and has a single definition, but is used in multiple places. It does not enable any sort of dynamic polymorphism that is not covered above. |
|||
<lang d>template registerable() { |
|||
void register() { /* implementation */ } |
|||
} |
|||
string makeFunction(string s) { |
|||
return `string `~s~`(){ return "`~s~`";}`; |
|||
} |
|||
class Foo { |
|||
mixin registerable!(); |
|||
mixin(makeFunction("myFunction")); |
|||
} |
|||
unittest { |
|||
import std.stdio : writeln; |
|||
Foo foo = new Foo; |
|||
foo.register(); |
|||
writeln(foo.myFunction()); |
|||
}</lang> |
|||
Using D's [[Compile-time calculation|CTFE]] and [[reflection]] capabilities, string mixins can copy the interface of other types , and thus be used for proxies and mocks. |
|||
=={{header|Delphi}}== |
=={{header|Delphi}}== |