Inheritance/Multiple: Difference between revisions
Added PowerShell |
PascalABC.NET |
||
(51 intermediate revisions by 28 users not shown) | |||
Line 1: | Line 1: | ||
{{Task|Basic language learning}} |
{{Task|Basic language learning}} |
||
[[Category:Object oriented]] |
[[Category:Object oriented]] |
||
[[Category:Type System]] |
|||
Multiple inheritance allows to specify that one [[classes | class]] is a subclass of several other classes. |
Multiple inheritance allows to specify that one [[classes | class]] is a subclass of several other classes. |
||
Some languages allow multiple [[inheritance]] for arbitrary classes, |
|||
others restrict it to interfaces, some don't allow it at all. |
|||
Some languages allow multiple [[inheritance]] for arbitrary classes, others restrict it to interfaces, some don't allow it at all. |
|||
Write two classes (or interfaces) <tt>Camera</tt> and <tt>MobilePhone</tt>, |
|||
then write a class <tt>CameraPhone</tt> which is both a <tt>Camera</tt> and |
|||
a <tt>MobilePhone</tt>. |
|||
;Task: |
|||
Write two classes (or interfaces) <tt>Camera</tt> and <tt>MobilePhone</tt>, then write a class <tt>CameraPhone</tt> which is both a <tt>Camera</tt> and a <tt>MobilePhone</tt>. |
|||
There is no need to implement any functions for those classes. |
There is no need to implement any functions for those classes. |
||
<br><br> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
Ada 2005 has added interfaces, allowing a limited form of multiple inheritance. |
Ada 2005 has added interfaces, allowing a limited form of multiple inheritance. |
||
< |
<syntaxhighlight lang="ada">package Multiple_Interfaces is |
||
type Camera is tagged null record; |
type Camera is tagged null record; |
||
type Mobile_Phone is limited Interface; |
type Mobile_Phone is limited Interface; |
||
type Camera_Phone is new Camera and Mobile_Phone with null record; |
type Camera_Phone is new Camera and Mobile_Phone with null record; |
||
end Multiple_Interfaces;</ |
end Multiple_Interfaces;</syntaxhighlight> |
||
{{omit from|Modula-2}} |
{{omit from|Modula-2}} |
||
=={{header|Aikido}}== |
=={{header|Aikido}}== |
||
Aikido does not support multiple inheritance, but does allow multiple implementation of interfaces. |
Aikido does not support multiple inheritance, but does allow multiple implementation of interfaces. |
||
< |
<syntaxhighlight lang="aikido">interface Camera { |
||
} |
} |
||
Line 29: | Line 32: | ||
class Camera_Phone implements Camera, Mobile_Phone { |
class Camera_Phone implements Camera, Mobile_Phone { |
||
}</ |
}</syntaxhighlight> |
||
=={{header|BBC BASIC}}== |
=={{header|BBC BASIC}}== |
||
{{works with|BBC BASIC for Windows}} |
{{works with|BBC BASIC for Windows}} |
||
< |
<syntaxhighlight lang="bbcbasic"> INSTALL @lib$+"CLASSLIB" |
||
DIM Camera{TakePicture} |
DIM Camera{TakePicture} |
||
Line 44: | Line 47: | ||
PROC_inherit(CameraPhone{}, Camera{}) |
PROC_inherit(CameraPhone{}, Camera{}) |
||
PROC_inherit(CameraPhone{}, MobilePhone{}) |
PROC_inherit(CameraPhone{}, MobilePhone{}) |
||
PROC_class(CameraPhone{})</ |
PROC_class(CameraPhone{})</syntaxhighlight> |
||
=={{header|C |
=={{header|C}}== |
||
C simulates Multiple Inheritance via Structures. |
|||
<lang cpp>class Camera |
|||
<syntaxhighlight lang="c"> |
|||
{ |
|||
typedef struct{ |
|||
// ... |
|||
double focalLength; |
|||
}; |
|||
double resolution; |
|||
double memory; |
|||
}Camera; |
|||
typedef struct{ |
|||
class MobilePhone |
|||
double balance; |
|||
{ |
|||
double batteryLevel; |
|||
// ... |
|||
char** contacts; |
|||
}; |
|||
}Phone; |
|||
typedef struct{ |
|||
class CameraPhone: |
|||
Camera cameraSample; |
|||
public Camera, |
|||
Phone phoneSample; |
|||
public MobilePhone |
|||
}CameraPhone; |
|||
{ |
|||
</syntaxhighlight> |
|||
// ... |
|||
};</lang> |
|||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
Line 71: | Line 77: | ||
In the example we inherit from a class and an interface. |
In the example we inherit from a class and an interface. |
||
< |
<syntaxhighlight lang="csharp">interface ICamera { |
||
// ... |
// ... |
||
} |
} |
||
Line 81: | Line 87: | ||
class CameraPhone: ICamera, MobilePhone { |
class CameraPhone: ICamera, MobilePhone { |
||
// ... |
// ... |
||
}</ |
}</syntaxhighlight> |
||
=={{header|C++}}== |
|||
<syntaxhighlight lang="cpp">class Camera |
|||
{ |
|||
// ... |
|||
}; |
|||
class MobilePhone |
|||
{ |
|||
// ... |
|||
}; |
|||
class CameraPhone: |
|||
public Camera, |
|||
public MobilePhone |
|||
{ |
|||
// ... |
|||
};</syntaxhighlight> |
|||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
< |
<syntaxhighlight lang="clojure">(defprotocol Camera) |
||
(defprotocol MobilePhone) |
(defprotocol MobilePhone) |
||
Line 90: | Line 114: | ||
(deftype CameraPhone [] |
(deftype CameraPhone [] |
||
Camera |
Camera |
||
MobilePhone)</ |
MobilePhone)</syntaxhighlight> |
||
=={{header|COBOL}}== |
=={{header|COBOL}}== |
||
< |
<syntaxhighlight lang="cobol"> IDENTIFICATION DIVISION. |
||
CLASS-ID. Camera. |
|||
*> ... |
*> ... |
||
END CLASS Camera. |
END CLASS Camera. |
||
IDENTIFICATION DIVISION. |
|||
CLASS-ID. Mobile-Phone. |
CLASS-ID. Mobile-Phone. |
||
*> ... |
*> ... |
||
END CLASS Mobile-Phone. |
END CLASS Mobile-Phone. |
||
IDENTIFICATION DIVISION. |
|||
CLASS-ID. Camera-Phone INHERITS Camera, Mobile-Phone. |
|||
CLASS-ID. Camera-Phone |
|||
INHERITS FROM Camera, Mobile-Phone. |
|||
ENVIRONMENT DIVISION. |
ENVIRONMENT DIVISION. |
||
CONFIGURATION SECTION. |
CONFIGURATION SECTION. |
||
Line 109: | Line 137: | ||
*> ... |
*> ... |
||
END CLASS Camera-Phone.</ |
END CLASS Camera-Phone.</syntaxhighlight> |
||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
< |
<syntaxhighlight lang="lisp">(defclass camera () ()) |
||
(defclass mobile-phone () ()) |
(defclass mobile-phone () ()) |
||
(defclass camera-phone (camera mobile-phone) ())</ |
(defclass camera-phone (camera mobile-phone) ())</syntaxhighlight> |
||
=={{header|D}}== |
=={{header|D}}== |
||
D |
While D does not have multiple base class inheritance, you can inherit from multiple interfaces. |
||
< |
<syntaxhighlight lang="d">interface Camera { |
||
// member function prototypes and static methods |
// member function prototypes and static methods |
||
} |
} |
||
Line 132: | Line 160: | ||
// member function implementations for Camera, |
// member function implementations for Camera, |
||
// MobilePhone, and CameraPhone |
// MobilePhone, and CameraPhone |
||
}</ |
}</syntaxhighlight> |
||
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. |
|||
<syntaxhighlight 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(); |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
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 did. |
|||
<syntaxhighlight 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()); |
|||
}</syntaxhighlight> |
|||
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. |
|||
<syntaxhighlight 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()); |
|||
}</syntaxhighlight> |
|||
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}}== |
||
Delphi doesn't support multiple inheritance, but it does have multiple interfaces. |
Delphi doesn't support multiple inheritance, but it does have multiple interfaces. |
||
<syntaxhighlight lang="delphi">type |
|||
<lang Delphi>type |
|||
ICamera = Interface |
ICamera = Interface |
||
// ICamera methods... |
// ICamera methods... |
||
Line 150: | Line 258: | ||
TCameraPhone = class(TInterfacedObject, ICamera, IMobilePhone) |
TCameraPhone = class(TInterfacedObject, ICamera, IMobilePhone) |
||
// ICamera and IMobilePhone methods... |
// ICamera and IMobilePhone methods... |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|DWScript}}== |
=={{header|DWScript}}== |
||
Line 167: | Line 275: | ||
These shortcomings could be fixed if more powerful multiple inheritance were needed. |
These shortcomings could be fixed if more powerful multiple inheritance were needed. |
||
< |
<syntaxhighlight lang="e">def minherit(self, supers) { |
||
def forwarder match [verb, args] { |
def forwarder match [verb, args] { |
||
escape __return { |
escape __return { |
||
Line 189: | Line 297: | ||
} |
} |
||
return forwarder |
return forwarder |
||
}</ |
}</syntaxhighlight> |
||
The task example: |
The task example: |
||
< |
<syntaxhighlight lang="e">def makeCamera(self) { |
||
return def camera extends minherit(self, []) { |
return def camera extends minherit(self, []) { |
||
to takesPictures() { return true } |
to takesPictures() { return true } |
||
Line 215: | Line 323: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
And testing that it works as intended: |
And testing that it works as intended: |
||
<syntaxhighlight lang="e"> |
|||
<lang e> |
|||
? def p := makeCameraPhone(p) |
? def p := makeCameraPhone(p) |
||
> [p.takesPictures(), p.makesCalls(), p.internalMemory()] |
> [p.takesPictures(), p.makesCalls(), p.internalMemory()] |
||
# value: [true, true, 33619968]</ |
# value: [true, true, 33619968]</syntaxhighlight> |
||
=={{header|Eiffel}}== |
=={{header|Eiffel}}== |
||
Having two class—one for CAMERA and the other for a MOBILE_PHONE ... |
|||
<lang eiffel >class |
|||
<syntaxhighlight lang="eiffel ">class |
|||
CAMERA |
CAMERA |
||
end</ |
end</syntaxhighlight> |
||
< |
<syntaxhighlight lang="eiffel ">class |
||
MOBILE_PHONE |
MOBILE_PHONE |
||
end</ |
end</syntaxhighlight> |
||
=== Now Multiple Inherit === |
|||
<lang eiffel >class |
|||
We can create a new CAMERA_PHONE, which inherits directly from both CAMERA and MOBILE_PHONE. |
|||
<syntaxhighlight lang="eiffel ">class |
|||
CAMERA_PHONE |
CAMERA_PHONE |
||
inherit |
inherit |
||
CAMERA |
CAMERA |
||
MOBILE_PHONE |
MOBILE_PHONE |
||
end</ |
end</syntaxhighlight> |
||
NOTE: There is no reasonable limit to the number of classes we can inherit from in a single class. The compiler helps us to navigate issues like repeated inheritance and the "diamond of death" easily and quickly. |
|||
=={{header|Elena}}== |
=={{header|Elena}}== |
||
ELENA only permits inheritance from one parent class. However, mixins are supported |
ELENA only permits inheritance from one parent class. However, mixins are supported |
||
<syntaxhighlight lang="elena">singleton CameraFeature |
|||
<lang elena>#import system. |
|||
#symbol CameraFeature = |
|||
{ |
{ |
||
cameraMsg |
|||
= "camera" |
= "camera"; |
||
} |
} |
||
class MobilePhone |
|||
{ |
{ |
||
mobileMsg |
|||
= "phone" |
= "phone"; |
||
} |
} |
||
class CameraPhone : MobilePhone |
|||
{ |
{ |
||
dispatch() => CameraFeature; |
|||
} |
} |
||
public program() |
|||
{ |
|||
[ |
|||
var cp := new CameraPhone(); |
|||
console |
console.writeLine(cp.cameraMsg); |
||
console |
console.writeLine(cp.mobileMsg) |
||
}</syntaxhighlight> |
|||
].</lang> |
|||
Alternatively a group object may be created |
Alternatively a group object may be created |
||
< |
<syntaxhighlight lang="elena">import system'dynamic; |
||
#import system'dynamic. |
|||
class CameraFeature |
|||
{ |
{ |
||
cameraMsg |
|||
= "camera" |
= "camera"; |
||
} |
} |
||
class MobilePhone |
|||
{ |
{ |
||
mobileMsg |
|||
= "phone" |
= "phone"; |
||
} |
} |
||
singleton CameraPhone |
|||
{ |
{ |
||
new() = new MobilePhone().mixInto(new CameraFeature()); |
|||
new = MobilePhone new mix &into:(CameraFeature new). |
|||
} |
} |
||
public program() |
|||
{ |
|||
[ |
|||
var cp := CameraPhone.new(); |
|||
console.writeLine(cp.cameraMsg); |
|||
console.writeLine(cp.mobileMsg) |
|||
}</syntaxhighlight> |
|||
=={{header|F_Sharp|F#}}== |
|||
A class can only inherit from one other class, but it can implement any number of interfaces. |
|||
<syntaxhighlight lang="fsharp">type Picture = System.Drawing.Bitmap // (a type synonym) |
|||
// an interface type |
|||
type Camera = |
|||
abstract takePicture : unit -> Picture |
|||
// an interface that inherits multiple interfaces |
|||
type Camera2 = |
|||
inherits System.ComponentModel.INotifyPropertyChanged |
|||
inherits Camera |
|||
// a class with an abstract method with a default implementation |
|||
// (usually called a virtual method) |
|||
type MobilePhone() = |
|||
abstract makeCall : int[] -> unit |
|||
default x.makeCall(number) = () // empty impl |
|||
// a class that inherits from another class and implements an interface |
|||
type CameraPhone() = |
|||
inherit MobilePhone() |
|||
interface Camera with |
|||
member x.takePicture() = new Picture(10, 10)</syntaxhighlight> |
|||
=={{header|Factor}}== |
|||
console writeLine:(cp cameraMsg). |
|||
<syntaxhighlight lang="factor">TUPLE: camera ; |
|||
console writeLine:(cp mobileMsg). |
|||
TUPLE: mobile-phone ; |
|||
].</lang> |
|||
UNION: camera-phone camera mobile-phone ;</syntaxhighlight> |
|||
=={{header|Fantom}}== |
=={{header|Fantom}}== |
||
Line 303: | Line 443: | ||
It is an error for method names to conflict. |
It is an error for method names to conflict. |
||
< |
<syntaxhighlight lang="fantom">// a regular class |
||
class Camera |
class Camera |
||
{ |
{ |
||
Line 334: | Line 474: | ||
echo (cp.mobileMsg) |
echo (cp.mobileMsg) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|F_Sharp|F#}}== |
|||
A class can only inherit from one other class, but it can implement any number of interfaces. |
|||
=={{header|Forth}}== |
|||
<lang fsharp>type Picture = System.Drawing.Bitmap // (a type synonym) |
|||
Standard Forth does not supply high level data structures |
|||
// an interface type |
|||
or functions. But there is library code written by vendors |
|||
type Camera = |
|||
or users. For object programming with multiple inheritance |
|||
abstract takePicture : unit -> Picture |
|||
there is a user-supplied ANS compatible extension. |
|||
https://github.com/DouglasBHoffman/FMS2 |
|||
// a class with an abstract method with a default implementation |
|||
Download the FMSMI package to run the |
|||
// (usually called a virtual method) |
|||
following example code. |
|||
type MobilePhone() = |
|||
abstract makeCall : int[] -> unit |
|||
default x.makeCall(number) = () // empty impl |
|||
<syntaxhighlight lang="forth"> |
|||
// a class that inherits from another class and implements an interface |
|||
type CameraPhone() = |
|||
inherit MobilePhone() |
|||
interface Camera with |
|||
member x.takePicture() = new Picture(10, 10)</lang> |
|||
\ define class camera with method say: |
|||
=={{header|Forth}}== |
|||
:class camera |
|||
{{works with|Forth}} |
|||
:m say: ." camera " ;m |
|||
Works with any ANS Forth. This extension fully supports true multiple inheritance. |
|||
;class |
|||
Needs the FMS-MI (multiple inheritance) library code located here: |
|||
http://soton.mpeforth.com/flag/fms/index.html |
|||
<lang forth>include FMS-MIBuildGen.f |
|||
include FMS-MIHarnGen.f |
|||
include FMS-MI.f |
|||
\ define class phone with method say: |
|||
:class Camera |
|||
:class phone |
|||
:m say: ." phone " ;m |
|||
;class |
;class |
||
\ define cameraPhone phone with method say: |
|||
:class MobilePhone |
|||
\ class cameraPhone inherits from both class |
|||
\ camera and class phone |
|||
:class cameraPhone super{ camera phone } |
|||
:m say: self say: \ method conflicts in superclasses |
|||
\ are resolved by left-to-right order |
|||
\ so self say: will call the say: method |
|||
\ from class camera |
|||
super> phone say: \ super> phone is used to direct |
|||
\ this say: method to use the |
|||
\ method from class phone |
|||
;m |
|||
;class |
;class |
||
cameraPhone cp \ instantiate a cameraPhone object named cp |
|||
:class CameraPhone super{ Camera MobilePhone } \ any number of superclasses may be used |
|||
;class |
|||
cp say: \ send the say: message to cp |
|||
CameraPhone cf \ instantiate a CameraPhone object named cf</lang> |
|||
\ output: |
|||
camera phone |
|||
</syntaxhighlight> |
|||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64 |
|||
' FB does not currently support multiple inheritance. Composition has to be used instead if one wants |
|||
' to (effectively) inherit from more than one class. In some cases, this might arguably be a better |
|||
' solution anyway. |
|||
Type Camera Extends Object ' if virtual methods etc needed |
|||
' ... |
|||
End Type |
|||
Type Phone Extends Object |
|||
' ... |
|||
End Type |
|||
Type CameraPhone Extends Phone ' single inheritance |
|||
cam As Camera ' using composition here |
|||
' other stuff |
|||
End Type</syntaxhighlight> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
Go abandons traditional object oriented concepts of inheritance hierarchies, yet it does have features for composing both structs and interfaces. |
Go abandons traditional object oriented concepts of inheritance hierarchies, yet it does have features for composing both structs and interfaces. |
||
< |
<syntaxhighlight lang="go">// Example of composition of anonymous structs |
||
package main |
package main |
||
Line 409: | Line 574: | ||
htc.sim = "XYZ" |
htc.sim = "XYZ" |
||
fmt.Println(htc) |
fmt.Println(htc) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} (Note sensor field still blank) |
{{out}} (Note sensor field still blank) |
||
<pre>{{zoom } {XYZ 3.14}}</pre> |
<pre>{{zoom } {XYZ 3.14}}</pre> |
||
< |
<syntaxhighlight lang="go">// Example of composition of interfaces. |
||
// Types implement interfaces simply by implementing functions. |
// Types implement interfaces simply by implementing functions. |
||
// The type does not explicitly declare the interfaces it implements. |
// The type does not explicitly declare the interfaces it implements. |
||
Line 458: | Line 623: | ||
i.photo() |
i.photo() |
||
i.call() |
i.call() |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 464: | Line 629: | ||
omg! |
omg! |
||
</pre> |
</pre> |
||
=={{header|Groovy}}== |
|||
Same inheritance rules as [[Inheritance/Multiple#Java|Java]]. |
|||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">class Camera a |
||
class MobilePhone a |
class MobilePhone a |
||
class (Camera a, MobilePhone a) => CameraPhone a</ |
class (Camera a, MobilePhone a) => CameraPhone a</syntaxhighlight> |
||
==Icon and {{header|Unicon}}== |
==Icon and {{header|Unicon}}== |
||
Line 477: | Line 645: | ||
This became one of the major addons contributing to Unicon. |
This became one of the major addons contributing to Unicon. |
||
< |
<syntaxhighlight lang="unicon">class Camera (instanceVars) |
||
# methods... |
# methods... |
||
# initializer... |
# initializer... |
||
Line 490: | Line 658: | ||
# methods... |
# methods... |
||
# initialiser... |
# initialiser... |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Io}}== |
|||
<syntaxhighlight lang="io">Camera := Object clone |
|||
Camera click := method("Taking snapshot" println) |
|||
MobilePhone := Object clone |
|||
MobilePhone call := method("Calling home" println) |
|||
CameraPhone := Camera clone |
|||
CameraPhone appendProto(MobilePhone) |
|||
myPhone := CameraPhone clone |
|||
myPhone click // --> "Taking snapshot" |
|||
myPhone call // --> "Calling home"</syntaxhighlight> |
|||
In Io each object has an internal list of prototype objects it inherits from. You can add to this list with <code>appendProto</code>. |
|||
=={{header|Ioke}}== |
=={{header|Ioke}}== |
||
< |
<syntaxhighlight lang="ioke">Camera = Origin mimic |
||
MobilePhone = Origin mimic |
MobilePhone = Origin mimic |
||
CameraPhone = Camera mimic mimic!(MobilePhone)</ |
CameraPhone = Camera mimic mimic!(MobilePhone)</syntaxhighlight> |
||
=={{header|J}}== |
=={{header|J}}== |
||
< |
<syntaxhighlight lang="j">coclass 'Camera' |
||
create=: verb define |
create=: verb define |
||
Line 529: | Line 712: | ||
destroy=: codestroy |
destroy=: codestroy |
||
NB. additional camera-phone methods go here</ |
NB. additional camera-phone methods go here</syntaxhighlight> |
||
The adverb Fix (f.) is needed as shown so the superclass constructors |
The adverb Fix (f.) is needed as shown so the superclass constructors |
||
get executed in the object, not in the superclass. |
get executed in the object, not in the superclass. |
||
Line 536: | Line 719: | ||
Java does not allow multiple inheritance, but you can "implement" multiple interfaces. All methods in interfaces are abstract (they don't have an implementation). |
Java does not allow multiple inheritance, but you can "implement" multiple interfaces. All methods in interfaces are abstract (they don't have an implementation). |
||
When you implement an interface you need to implement the specified methods. |
When you implement an interface you need to implement the specified methods. |
||
< |
<syntaxhighlight lang="java">public interface Camera{ |
||
//functions here with no definition... |
//functions here with no definition... |
||
//ex: |
//ex: |
||
//public void takePicture(); |
//public void takePicture(); |
||
}</ |
}</syntaxhighlight> |
||
< |
<syntaxhighlight lang="java">public interface MobilePhone{ |
||
//functions here with no definition... |
//functions here with no definition... |
||
//ex: |
//ex: |
||
//public void makeCall(); |
//public void makeCall(); |
||
}</ |
}</syntaxhighlight> |
||
< |
<syntaxhighlight lang="java">public class CameraPhone implements Camera, MobilePhone{ |
||
//functions here... |
//functions here... |
||
}</ |
}</syntaxhighlight> |
||
{{omit|Julia}} |
|||
=={{header|Julia}}== |
|||
Julia supports inheritance via abstract types. In Julia, multiple dispatch allows objects of different types to have the same function interfaces. Julia also can support traits via parameters in type declarations or with macros. This makes multiple inheritance in Julia mostly unnecessary, except for the inconvenience of composing the data in a mixed type when declaring multiple similar types, for which there are macros.<br /> <br />For example, the functions <code> dialnumber(equipment, name) </code> and <code> video(equipment, filename) </code> could be used as generic interfaces to implement methods for a <code>Telephone</code>, a <code>Camera</code>, and a <code>SmartPhone</code>, and Julia would dispatch according to the type of the equipment.<syntaxhighlight lang="julia"> |
|||
abstract type Phone end |
|||
struct DeskPhone <: Phone |
|||
book::Dict{String,String} |
|||
end |
|||
abstract type Camera end |
|||
struct kodak |
|||
roll::Vector{Array{Int32,2}} |
|||
end |
|||
struct CellPhone <: Phone |
|||
book::Dict{String,String} |
|||
roll::Vector{AbstractVector} |
|||
end |
|||
function dialnumber(phone::CellPhone) |
|||
println("beep beep") |
|||
end |
|||
function dialnumber(phone::Phone) |
|||
println("tat tat tat tat") |
|||
end |
|||
function snap(camera, img) |
|||
println("click") |
|||
push!(camera.roll, img) |
|||
end |
|||
dphone = DeskPhone(Dict(["information" => "411"])) |
|||
cphone = CellPhone(Dict(["emergency" => "911"]), [[]]) |
|||
dialnumber(dphone) |
|||
dialnumber(cphone) |
|||
</syntaxhighlight>{{output}}<pre> |
|||
tat tat tat tat |
|||
beep beep |
|||
</pre> |
|||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
Line 555: | Line 783: | ||
to be abstract or to provide accessor implementations. |
to be abstract or to provide accessor implementations. |
||
<syntaxhighlight lang="scala">interface Camera { |
|||
<lang scala>package multiple_inheritance |
|||
interface Camera { |
|||
val numberOfLenses : Int |
val numberOfLenses : Int |
||
} |
} |
||
Line 563: | Line 789: | ||
interface MobilePhone { |
interface MobilePhone { |
||
fun charge(n : Int) { |
fun charge(n : Int) { |
||
if (n >= 0) |
if (n >= 0) |
||
battery_level |
battery_level = (battery_level + n).coerceAtMost(100) |
||
if (battery_level > 100) battery_level = 100 |
|||
} |
|||
} |
} |
||
Line 577: | Line 801: | ||
fun main(args: Array<String>) { |
fun main(args: Array<String>) { |
||
val c = CameraPhone(1, 50) |
val c = CameraPhone(1, 50) |
||
println(c) |
println(c) |
||
c.charge(35) |
c.charge(35) |
||
println(c) |
|||
c.charge(78) |
|||
println(c) |
println(c) |
||
println(listOf(c.javaClass.superclass) + c.javaClass.interfaces) |
println(listOf(c.javaClass.superclass) + c.javaClass.interfaces) |
||
Line 585: | Line 810: | ||
println(c2) |
println(c2) |
||
println(listOf(c2.javaClass.superclass) + c2.javaClass.interfaces) |
println(listOf(c2.javaClass.superclass) + c2.javaClass.interfaces) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>CameraPhone(numberOfLenses=1, battery_level=50) |
<pre>CameraPhone(numberOfLenses=1, battery_level=50) |
||
CameraPhone(numberOfLenses=1, battery_level=85) |
CameraPhone(numberOfLenses=1, battery_level=85) |
||
CameraPhone(numberOfLenses=1, battery_level=100) |
|||
[class java.lang.Object, interface multiple_inheritance.Camera, interface multiple_inheritance.MobilePhone] |
[class java.lang.Object, interface multiple_inheritance.Camera, interface multiple_inheritance.MobilePhone] |
||
TwinLensCamera(numberOfLenses=2) |
TwinLensCamera(numberOfLenses=2) |
||
Line 598: | Line 824: | ||
and trays hand down the methods it has implemented provided that the type |
and trays hand down the methods it has implemented provided that the type |
||
fulfills the requirements for the trait. [http://lassoguide.com/language/traits.html http://lassoguide.com/language/traits.html] |
fulfills the requirements for the trait. [http://lassoguide.com/language/traits.html http://lassoguide.com/language/traits.html] |
||
< |
<syntaxhighlight lang="lasso">define trait_camera => trait { |
||
require zoomfactor |
require zoomfactor |
||
Line 634: | Line 860: | ||
#mydevice -> has_zoom |
#mydevice -> has_zoom |
||
'<br />' |
'<br />' |
||
#mydevice -> is_smart</ |
#mydevice -> is_smart</syntaxhighlight> |
||
-> false |
-> false |
||
true |
true |
||
=={{header|Latitude}}== |
|||
Latitude is a prototype-oriented language, and every object can have only one prototype. As such, multiple inheritance in the usual sense is impossible in Latitude. The behavior of multiple (implementation) inheritance can be approximated with mixins. |
|||
<syntaxhighlight lang="latitude">Camera ::= Mixin clone. |
|||
MobilePhone ::= Mixin clone. |
|||
CameraPhone ::= Object clone. |
|||
Camera inject: CameraPhone. |
|||
MobilePhone inject: CameraPhone.</syntaxhighlight> |
|||
In order to add functionality to either of the mixins, the <code>interface</code> slot of the mixin must be modified to include the name of the new method. Injecting a mixin makes a copy of the methods, as opposed to traditional (prototype) inheritance in which method calls are delegated. |
|||
=={{header|Lingo}}== |
|||
Lingo does not support multiple inheritance. But its slightly idiosyncratic inheritance implementation based on "ancestors" allows to assign/change inheritance relations at runtime. So a similar (but not identical) effect can be achieved by something like this: |
|||
<syntaxhighlight lang="lingo">-- parent script "Camera" |
|||
property resolution |
|||
on new (me) |
|||
me.resolution = "1024x768" |
|||
return me |
|||
end |
|||
on snap (me) |
|||
put "SNAP!" |
|||
end</syntaxhighlight> |
|||
<syntaxhighlight lang="lingo">-- parent script "MobilePhone" |
|||
property ringtone |
|||
on new (me) |
|||
me.ringtone = "Bell" |
|||
return me |
|||
end |
|||
on ring (me, n) |
|||
repeat with i = 1 to n |
|||
put "RING!!!" |
|||
end repeat |
|||
end</syntaxhighlight> |
|||
<syntaxhighlight lang="lingo">-- parent script "CameraPhone" |
|||
property ancestor |
|||
on new (me) |
|||
c = script("Camera").new() |
|||
mp = script("MobilePhone").new() |
|||
-- make the Camera instance a parent of the MobilePhone instance |
|||
mp.setProp(#ancestor, c) |
|||
-- make the MobilePhone instance a parent of this CameraPhone instance |
|||
me.ancestor = mp |
|||
return me |
|||
end</syntaxhighlight> |
|||
Usage: |
|||
<syntaxhighlight lang="lingo">cp = script("CameraPhone").new() |
|||
cp.snap() |
|||
-- "SNAP!" |
|||
cp.ring(3) |
|||
-- "RING!!!" |
|||
-- "RING!!!" |
|||
-- "RING!!!" |
|||
put cp.resolution |
|||
-- "1024x768" |
|||
put cp.ringtone |
|||
-- "Bell"</syntaxhighlight> |
|||
=={{header|Logtalk}}== |
=={{header|Logtalk}}== |
||
Line 643: | Line 943: | ||
There is no "class" keyword in Logtalk; |
There is no "class" keyword in Logtalk; |
||
an "object" keyword is used instead (Logtalk objects play the role of classes, meta-classes, instances, or prototypes depending on the relations with other objects). |
an "object" keyword is used instead (Logtalk objects play the role of classes, meta-classes, instances, or prototypes depending on the relations with other objects). |
||
< |
<syntaxhighlight lang="logtalk">:- object(camera, |
||
...). |
...). |
||
... |
... |
||
:- end_object.</ |
:- end_object.</syntaxhighlight> |
||
< |
<syntaxhighlight lang="logtalk">:- object(mobile_phone, |
||
...). |
...). |
||
... |
... |
||
:- end_object.</ |
:- end_object.</syntaxhighlight> |
||
< |
<syntaxhighlight lang="logtalk">:- object(camera_phone, |
||
specializes(camera, mobile_phone), |
specializes(camera, mobile_phone), |
||
...). |
...). |
||
... |
... |
||
:- end_object.</ |
:- end_object.</syntaxhighlight> |
||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
Line 664: | Line 964: | ||
by making it a closure. |
by making it a closure. |
||
< |
<syntaxhighlight lang="lua">function setmetatables(t,mts) --takes a table and a list of metatables |
||
return setmetatable(t,{__index = function(self, k) |
return setmetatable(t,{__index = function(self, k) |
||
--collisions are resolved in this implementation by simply taking the first one that comes along. |
--collisions are resolved in this implementation by simply taking the first one that comes along. |
||
Line 676: | Line 976: | ||
camera = {} |
camera = {} |
||
mobilephone = {} |
mobilephone = {} |
||
cameraphone = setemetatables({},{camera,mobilephone})</ |
cameraphone = setemetatables({},{camera,mobilephone})</syntaxhighlight> |
||
=={{header|M2000 Interpreter}}== |
|||
<syntaxhighlight lang="m2000 interpreter"> |
|||
Module CheckIt { |
|||
Class Camera { |
|||
Private: |
|||
cameratype$ |
|||
Class: |
|||
module Camera (.cameratype$){ |
|||
} |
|||
} |
|||
\\ INHERITANCE AT CODE LEVEL |
|||
Class MobilePhone { |
|||
Private: |
|||
model$ |
|||
Class: |
|||
module MobilePhone (.model$) { |
|||
} |
|||
} |
|||
Class CameraPhone as Camera as MobilePhone { |
|||
Module CameraPhone ( .model$, .cameratype$) { |
|||
} |
|||
} |
|||
CP1 =CameraPhone("X-15", "OBSCURE") |
|||
Print CP1 is type CameraPhone = true |
|||
Print CP1 is type Camera = true |
|||
Print CP1 is type MobilePhone = true |
|||
\\ INHERITANCE AT OBJECT LEVEL |
|||
CP2 = MobilePhone("X-9") with Camera("WIDE") |
|||
\\ CP3 has no type |
|||
Group CP3 { |
|||
Module PrintAll { |
|||
If this is type Camera and this is type MobilePhone then |
|||
Print .model$, .cameratype$ |
|||
Else |
|||
Print "Nothing to print" |
|||
End if |
|||
} |
|||
} |
|||
CP3.PrintAll ' Nothing to print |
|||
\\ using pointers and prepate inheritance at object level |
|||
CP->(CP1 with CP3) |
|||
CP=>PrintAll |
|||
CP->(CP2 with CP3) |
|||
CP=>PrintAll |
|||
} |
|||
CheckIt |
|||
</syntaxhighlight> |
|||
=={{header|Nemerle}}== |
=={{header|Nemerle}}== |
||
Like C#, Nemerle only allows pseudo-multiple inheritance through interfaces. |
Like C#, Nemerle only allows pseudo-multiple inheritance through interfaces. |
||
In Nemerle, the base class must be listed before any interfaces. |
In Nemerle, the base class must be listed before any interfaces. |
||
< |
<syntaxhighlight lang="nemerle">interface ICamera { |
||
// ... |
// ... |
||
} |
} |
||
Line 691: | Line 1,040: | ||
class CameraPhone: MobilePhone, ICamera { |
class CameraPhone: MobilePhone, ICamera { |
||
// ... |
// ... |
||
}</ |
}</syntaxhighlight> |
||
=={{header|NetRexx}}== |
=={{header|NetRexx}}== |
||
Line 700: | Line 1,049: | ||
In this sample the class/interface names are augmented over those required in the task to prevent namespace pollution. |
In this sample the class/interface names are augmented over those required in the task to prevent namespace pollution. |
||
The sample also provides a complete working implementation to demonstrate the capability. |
The sample also provides a complete working implementation to demonstrate the capability. |
||
< |
<syntaxhighlight lang="netrexx">/* NetRexx */ |
||
options replace format comments java crossref symbols binary |
options replace format comments java crossref symbols binary |
||
Line 745: | Line 1,094: | ||
return shutter |
return shutter |
||
method call() public |
method call() public |
||
return ringTone</ |
return ringTone</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 752: | Line 1,101: | ||
click... |
click... |
||
ring...</pre> |
ring...</pre> |
||
=={{header|Nim}}== |
|||
nim does not support multiple inheritance (version<=1.4.6). It is just a demonstration of the procedure reloading nature of nim code. |
|||
<syntaxhighlight lang="nim">type |
|||
Camera = ref object of RootObj |
|||
MobilePhone = ref object of RootObj |
|||
CameraPhone = object |
|||
camera: Camera |
|||
phone: MobilePhone |
|||
proc `is`(cp: CameraPhone, t: typedesc): bool = |
|||
for field in cp.fields(): |
|||
if field of t: |
|||
return true |
|||
var cp: CameraPhone |
|||
echo(cp is Camera) |
|||
echo(cp is MobilePhone)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
true |
|||
true</pre> |
|||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
Line 762: | Line 1,131: | ||
of multiple classes, you can use message forwarding to mimic the functionality of those classes without actually inheriting them, as described in [http://support.apple.com/kb/TA45894 this guide]: |
of multiple classes, you can use message forwarding to mimic the functionality of those classes without actually inheriting them, as described in [http://support.apple.com/kb/TA45894 this guide]: |
||
< |
<syntaxhighlight lang="objc">@interface Camera : NSObject { |
||
} |
} |
||
@end |
@end |
||
Line 814: | Line 1,183: | ||
} |
} |
||
@end</ |
@end</syntaxhighlight> |
||
Caveat: the CameraPhone class will still technically not inherit from |
Caveat: the CameraPhone class will still technically not inherit from |
||
Line 820: | Line 1,189: | ||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang="ocaml">class camera = |
||
object (self) |
object (self) |
||
(*functions go here...*) |
(*functions go here...*) |
||
end</ |
end</syntaxhighlight> |
||
< |
<syntaxhighlight lang="ocaml">class mobile_phone = |
||
object (self) |
object (self) |
||
(*functions go here...*) |
(*functions go here...*) |
||
end</ |
end</syntaxhighlight> |
||
< |
<syntaxhighlight lang="ocaml">class camera_phone = |
||
object (self) |
object (self) |
||
inherit camera |
inherit camera |
||
inherit mobile_phone |
inherit mobile_phone |
||
(*functions go here...*) |
(*functions go here...*) |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Oforth}}== |
=={{header|Oforth}}== |
||
Line 845: | Line 1,213: | ||
If Camera and MobilePhone are designed as properties, we can write : |
If Camera and MobilePhone are designed as properties, we can write : |
||
< |
<syntaxhighlight lang="oforth">Property new: Camera |
||
Property new: MobilePhone |
Property new: MobilePhone |
||
Object Class new: CameraPhone |
Object Class new: CameraPhone |
||
CameraPhone is: Camera |
CameraPhone is: Camera |
||
CameraPhone is: MobilePhone</ |
CameraPhone is: MobilePhone</syntaxhighlight> |
||
=={{header|ooRexx}}== |
=={{header|ooRexx}}== |
||
Line 856: | Line 1,224: | ||
Mixins are more than just interfaces. |
Mixins are more than just interfaces. |
||
They can contain concrete method implementations and also create instance variables (scoped as private variables to the mixin methods). |
They can contain concrete method implementations and also create instance variables (scoped as private variables to the mixin methods). |
||
<syntaxhighlight lang="oorexx"> |
|||
<lang ooRexx> |
|||
-- inherited classes must be created as mixinclasses. |
-- inherited classes must be created as mixinclasses. |
||
::class phone mixinclass object |
::class phone mixinclass object |
||
Line 870: | Line 1,238: | ||
-- or |
-- or |
||
::class cameraphone2 subclass camera inherit phone</ |
::class cameraphone2 subclass camera inherit phone</syntaxhighlight> |
||
=={{header|OxygenBasic}}== |
=={{header|OxygenBasic}}== |
||
< |
<syntaxhighlight lang="oxygenbasic">class Camera |
||
string cbuf |
string cbuf |
||
method TakePhoto() |
method TakePhoto() |
||
Line 896: | Line 1,264: | ||
cp.ViewPhoto |
cp.ViewPhoto |
||
cp.MakeCall</ |
cp.MakeCall</syntaxhighlight> |
||
=={{header|Oz}}== |
=={{header|Oz}}== |
||
< |
<syntaxhighlight lang="oz">class Camera end |
||
class MobilePhone end |
class MobilePhone end |
||
class CameraPhone from Camera MobilePhone end</ |
class CameraPhone from Camera MobilePhone end</syntaxhighlight> |
||
=={{header|Pascal}}== |
=={{header|Pascal}}== |
||
See [[Inheritance/Multiple#Delphi | Delphi]] |
See [[Inheritance/Multiple#Delphi | Delphi]] |
||
=={{header|PascalABC.NET}}== |
|||
In PascalABC.NET you may inherit from only one class, but you can inherit from multiple interfaces. |
|||
<syntaxhighlight lang="delphi"> |
|||
type |
|||
IMy1 = interface |
|||
procedure My1; |
|||
end; |
|||
IMy2 = interface |
|||
procedure My2; |
|||
end; |
|||
MyClass = class(IMy1,IMy2) |
|||
public |
|||
procedure My1 := Writeln('My1'); |
|||
procedure My2 := Writeln('My2'); |
|||
end; |
|||
MyClassD = class(MyClass,IMy1,IMy2) |
|||
end; |
|||
begin |
|||
var my := new MyClassD; |
|||
my.My1; my.My2; |
|||
end. |
|||
</syntaxhighlight> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">package Camera; |
||
#functions go here... |
#functions go here... |
||
1;</ |
1;</syntaxhighlight> |
||
< |
<syntaxhighlight lang="perl">package MobilePhone; |
||
#functions go here... |
#functions go here... |
||
1;</ |
1;</syntaxhighlight> |
||
< |
<syntaxhighlight lang="perl">package CameraPhone; |
||
use Camera; |
use Camera; |
||
use MobilePhone; |
use MobilePhone; |
||
@ISA = qw( Camera MobilePhone ); |
@ISA = qw( Camera MobilePhone ); |
||
#functions go here... |
#functions go here... |
||
1;</ |
1;</syntaxhighlight> |
||
or |
or |
||
< |
<syntaxhighlight lang="perl">package CameraPhone; |
||
use base qw/Camera MobilePhone/; |
use base qw/Camera MobilePhone/; |
||
#functions go here...</ |
#functions go here...</syntaxhighlight> |
||
The same using the [http://search.cpan.org/perldoc?MooseX::Declare MooseX::Declare] extention: |
The same using the [http://search.cpan.org/perldoc?MooseX::Declare MooseX::Declare] extention: |
||
< |
<syntaxhighlight lang="perl">use MooseX::Declare; |
||
class Camera { |
class Camera { |
||
Line 941: | Line 1,334: | ||
class CameraPhone extends(Camera, MobilePhone) { |
class CameraPhone extends(Camera, MobilePhone) { |
||
# methods ... |
# methods ... |
||
}</ |
}</syntaxhighlight> |
||
=={{header| |
=={{header|Phix}}== |
||
{{libheader|Phix/Class}} |
|||
Needs 0.8.1+ |
|||
{{works with|Rakudo|2012.06}} |
|||
===inheritance=== |
|||
<lang perl6>class Camera {} |
|||
The programmer is expected to assume complete responsibility (away from the compiler) for checking/resolving any conflicts. |
|||
class MobilePhone {} |
|||
<syntaxhighlight lang="phix"> |
|||
class CameraPhone is Camera is MobilePhone {} |
|||
class Camra |
|||
string name = "nikkon" |
|||
say CameraPhone.^mro; # undefined type object |
|||
end class |
|||
say CameraPhone.new.^mro; # instantiated object</lang> |
|||
class Mobile |
|||
-- string name = "nokia" -- oops! |
|||
string mane = "nokia" -- ok! |
|||
end class |
|||
class CamraPhone extends Camra,Mobile |
|||
procedure show() ?{name,mane} end procedure |
|||
end class |
|||
CamraPhone cp = new() |
|||
cp.show()</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre> |
|||
<pre>CameraPhone() Camera() MobilePhone() Any() Mu() |
|||
{"nikkon","nokia"} |
|||
CameraPhone() Camera() MobilePhone() Any() Mu()</pre> |
|||
</pre> |
|||
===composition=== |
|||
The <tt>.^mro</tt> is not an ordinary method call, |
|||
The programmer is expected to assume complete responsibility for invoking new() appropriately.<br> |
|||
but a call to the object's metaobject |
|||
The example below shows four different approaches to invoking all the new() that are needed (one pair commented out).<br> |
|||
that returns the method resolution order for this type. |
|||
Note that invoking new() inside a class definition creates shared references to a single instance.<br> |
|||
The compiler demands to be explicitly told what the inner/inlined new() on cp2 are actually for. |
|||
<syntaxhighlight lang="phix">class Camera |
|||
public string name = "nikkon" |
|||
end class |
|||
class MobilePhone |
|||
public string name = "nokia" -- (clash no more) |
|||
end class |
|||
class CameraPhone |
|||
-- Camera c = new() |
|||
-- MobilePhone m = new() |
|||
public Camera c |
|||
public MobilePhone m |
|||
procedure show() ?{c.name,m.name} end procedure |
|||
end class |
|||
Camera c = new({"canon"}) |
|||
MobilePhone m = new() |
|||
CameraPhone cp1 = new({c,m}), |
|||
cp2 = new({new("Camera"),new("MobilePhone")}), |
|||
cp3 = new() -- (internal/shared/NULL c,m) |
|||
cp3.c = new() -- (obviously c must be public) |
|||
cp3.m = new({"LG20"}) -- "" m "" "" |
|||
cp1.show() |
|||
cp2.show() |
|||
cp3.show() -- crashes without internal/above new()</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
{"canon","nokia"} |
|||
{"nikkon","nokia"} |
|||
{"nikkon","LG20"} |
|||
</pre> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
< |
<syntaxhighlight lang="picolisp">(class +Camera) |
||
(class +MobilePhone) |
|||
(class +MobilePhone) |
(class +CameraPhone +MobilePhone +Camera) |
||
</syntaxhighlight> |
|||
=={{header|Pop11}}== |
=={{header|Pop11}}== |
||
< |
<syntaxhighlight lang="pop11">;;; load object support |
||
lib objectclass; |
lib objectclass; |
||
Line 981: | Line 1,415: | ||
enddefine; |
enddefine; |
||
;;; methods go here</ |
;;; methods go here</syntaxhighlight> |
||
=={{header|PowerShell}}== |
=={{header|PowerShell}}== |
||
{{works with|PowerShell|5}} |
{{works with|PowerShell|5}} |
||
<syntaxhighlight lang="powershell"> |
|||
<lang PowerShell> |
|||
class Camera {} |
class Camera {} |
||
class MobilePhone {} |
class MobilePhone {} |
||
class CameraPhone : Camera, MobilePhone {} |
class CameraPhone : Camera, MobilePhone {} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|PureBasic}}== |
=={{header|PureBasic}}== |
||
Using the open-source precompiler [http://www.development-lounge.de/viewtopic.php?t=5915 SimpleOOP]. |
Using the open-source precompiler [http://www.development-lounge.de/viewtopic.php?t=5915 SimpleOOP]. |
||
< |
<syntaxhighlight lang="purebasic">Class Camera |
||
EndClass |
EndClass |
||
Line 1,001: | Line 1,434: | ||
Class CameraMobile Extends Camera Extends Mobil |
Class CameraMobile Extends Camera Extends Mobil |
||
EndClass</ |
EndClass</syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
< |
<syntaxhighlight lang="python">class Camera: |
||
pass #functions go here...</ |
pass #functions go here...</syntaxhighlight> |
||
< |
<syntaxhighlight lang="python">class MobilePhone: |
||
pass #functions go here...</ |
pass #functions go here...</syntaxhighlight> |
||
< |
<syntaxhighlight lang="python">class CameraPhone(Camera, MobilePhone): |
||
pass #functions go here...</ |
pass #functions go here...</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
Line 1,018: | Line 1,451: | ||
Mixins can be used to achieve some of the benefits of multiple inheritance. |
Mixins can be used to achieve some of the benefits of multiple inheritance. |
||
< |
<syntaxhighlight lang="racket">#lang racket |
||
(define camera<%> (interface ())) |
(define camera<%> (interface ())) |
||
Line 1,027: | Line 1,460: | ||
(super-new) |
(super-new) |
||
;; implement methods here |
;; implement methods here |
||
))</ |
))</syntaxhighlight> |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2012.06}} |
|||
<syntaxhighlight lang="raku" line>class Camera {} |
|||
class MobilePhone {} |
|||
class CameraPhone is Camera is MobilePhone {} |
|||
say CameraPhone.^mro; # undefined type object |
|||
say CameraPhone.new.^mro; # instantiated object</syntaxhighlight> |
|||
{{out}} |
|||
<pre>CameraPhone() Camera() MobilePhone() Any() Mu() |
|||
CameraPhone() Camera() MobilePhone() Any() Mu()</pre> |
|||
The <tt>.^mro</tt> is not an ordinary method call, |
|||
but a call to the object's metaobject |
|||
that returns the method resolution order for this type. |
|||
=={{header|Ring}}== |
|||
<syntaxhighlight lang="ring"> |
|||
# Project : Inheritance/Multiple |
|||
mergemethods(:CameraPhone,:MobilePhone) |
|||
o1 = new CameraPhone |
|||
? o1 |
|||
? o1.testCamera() |
|||
? o1.testMobilePhone() |
|||
func AddParentClassAttributes oObject,cClass |
|||
# Add Attributes |
|||
cCode = "oTempObject = new " + cClass |
|||
eval(cCode) |
|||
for cAttribute in Attributes(oTempObject) |
|||
AddAttribute(oObject,cAttribute) |
|||
cCode = "oObject." + cAttribute + " = oTempObject." + cAttribute |
|||
eval(cCode) |
|||
next |
|||
class Camera |
|||
Name = "Camera" |
|||
func testCamera |
|||
? "Message from testCamera" |
|||
class MobilePhone |
|||
Type = "Android" |
|||
func testMobilePhone |
|||
? "Message from MobilePhone" |
|||
class CameraPhone from Camera |
|||
# Add MobilePhone Attributes |
|||
AddParentClassAttributes(self,:MobilePhone) |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
name: Camera |
|||
type: Android |
|||
Message from testCamera |
|||
Message from MobilePhone |
|||
</pre> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
Ruby does not have multiple inheritance, but you can mix modules into classes: |
Ruby does not have multiple inheritance, but you can mix modules into classes: |
||
< |
<syntaxhighlight lang="ruby">module Camera |
||
# define methods here |
# define methods here |
||
end |
end |
||
Line 1,040: | Line 1,536: | ||
include Camera |
include Camera |
||
# define methods here |
# define methods here |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Rust}}== |
|||
<syntaxhighlight lang="rust">trait Camera {} |
|||
trait MobilePhone {} |
|||
trait CameraPhone: Camera + MobilePhone {}</syntaxhighlight> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
< |
<syntaxhighlight lang="scala">trait Camera |
||
trait MobilePhone |
trait MobilePhone |
||
class CameraPhone extends Camera with MobilePhone</ |
class CameraPhone extends Camera with MobilePhone</syntaxhighlight> |
||
=={{header|Self}}== |
=={{header|Self}}== |
||
Self is a class-free, object-oriented language, and as such, it uses prototypal inheritance instead of classical inheritance. This is an example of the relevant excerpts from a Self transporter fileout. Normally the object tree would be built and navigated within the graphical Self environment. |
Self is a class-free, object-oriented language, and as such, it uses prototypal inheritance instead of classical inheritance. This is an example of the relevant excerpts from a Self transporter fileout. Normally the object tree would be built and navigated within the graphical Self environment. |
||
< |
<syntaxhighlight lang="self">camera = ()</syntaxhighlight> |
||
< |
<syntaxhighlight lang="self">mobilePhone = ()</syntaxhighlight> |
||
< |
<syntaxhighlight lang="self">cameraPhone = (| cameraParent* = camera. mobilePhoneParent* = mobilePhone |)</syntaxhighlight> |
||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
< |
<syntaxhighlight lang="ruby">class Camera {}; |
||
class MobilePhone {}; |
class MobilePhone {}; |
||
class CameraPhone << Camera, MobilePhone {};</ |
class CameraPhone << Camera, MobilePhone {};</syntaxhighlight> |
||
=={{header|Slate}}== |
=={{header|Slate}}== |
||
< |
<syntaxhighlight lang="slate">define: #Camera. |
||
define: #MobilePhone. |
define: #MobilePhone. |
||
define: #CameraPhone &parents: {Camera. MobilePhone}.</ |
define: #CameraPhone &parents: {Camera. MobilePhone}.</syntaxhighlight> |
||
=={{header|Swift}}== |
=={{header|Swift}}== |
||
Like Objective-C, Swift does not allow multiple inheritance. However, you can conform to multiple protocols. |
Like Objective-C, Swift does not allow multiple inheritance. However, you can conform to multiple protocols. |
||
< |
<syntaxhighlight lang="swift">protocol Camera { |
||
} |
} |
||
Line 1,075: | Line 1,577: | ||
class CameraPhone: Camera, Phone { |
class CameraPhone: Camera, Phone { |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
{{works with|Tcl|8.6}} or {{libheader|TclOO}} |
{{works with|Tcl|8.6}} or {{libheader|TclOO}} |
||
< |
<syntaxhighlight lang="tcl">package require TclOO |
||
oo::class create Camera |
oo::class create Camera |
||
Line 1,085: | Line 1,587: | ||
oo::class create CameraPhone { |
oo::class create CameraPhone { |
||
superclass Camera MobilePhone |
superclass Camera MobilePhone |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Wren}}== |
|||
Wren does not support either multiple inheritance or interfaces. |
|||
However, multiple inheritance can be simulated by inheriting from a single class and then embedding objects of other classes and wrapping their methods. |
|||
<syntaxhighlight lang="wren">class Camera { |
|||
construct new() {} |
|||
snap() { System.print("taking a photo") } |
|||
} |
|||
class Phone { |
|||
construct new() {} |
|||
call() { System.print("calling home") } |
|||
} |
|||
class CameraPhone is Camera { |
|||
construct new(phone) { _phone = phone } // uses composition for the Phone part |
|||
// inherits Camera's snap() method |
|||
// Phone's call() method can be wrapped |
|||
call() { _phone.call() } |
|||
} |
|||
var p = Phone.new() |
|||
var cp = CameraPhone.new(p) |
|||
cp.snap() |
|||
cp.call()</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
taking a photo |
|||
calling home |
|||
</pre> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
< |
<syntaxhighlight lang="zkl">class Camera{} class MobilePhone{} |
||
class CameraPhone(Camera,MobilePhone){} |
class CameraPhone(Camera,MobilePhone){} |
||
CameraPhone.linearizeParents</ |
CameraPhone.linearizeParents</syntaxhighlight> |
||
{{out}}Show the class search order |
{{out}}Show the class search order |
||
<pre>L(Class(CameraPhone),Class(Camera),Class(MobilePhone))</pre> |
<pre>L(Class(CameraPhone),Class(Camera),Class(MobilePhone))</pre> |
||
{{omit from|6502 Assembly}} |
|||
{{omit from|68000 Assembly}} |
|||
{{omit from|8080 Assembly}} |
|||
{{omit from|8086 Assembly}} |
|||
{{omit from|ARM Assembly}} |
|||
{{omit from|AWK}} |
{{omit from|AWK}} |
||
{{omit from|Axe}} |
|||
{{omit from|Batch File|Not an OO language.}} |
{{omit from|Batch File|Not an OO language.}} |
||
{{omit from|C|not really an OO language,single inheritance emulation is complex enough}} |
|||
{{omit from|JavaScript|https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Property_Inheritance_Revisited/No_Multiple_Inheritance}} |
{{omit from|JavaScript|https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Property_Inheritance_Revisited/No_Multiple_Inheritance}} |
||
{{omit from|Metafont}} |
{{omit from|Metafont}} |
||
Line 1,108: | Line 1,646: | ||
{{omit from|TI-83 BASIC|Does not have user-defined data structures or objects.}} |
{{omit from|TI-83 BASIC|Does not have user-defined data structures or objects.}} |
||
{{omit from|TI-89 BASIC|Does not have user-defined data structures or objects.}} |
{{omit from|TI-89 BASIC|Does not have user-defined data structures or objects.}} |
||
{{omit from| |
{{omit from|Z80 Assembly}} |
Latest revision as of 00:48, 24 June 2024
You are encouraged to solve this task according to the task description, using any language you may know.
Multiple inheritance allows to specify that one class is a subclass of several other classes.
Some languages allow multiple inheritance for arbitrary classes, others restrict it to interfaces, some don't allow it at all.
- Task
Write two classes (or interfaces) Camera and MobilePhone, then write a class CameraPhone which is both a Camera and a MobilePhone.
There is no need to implement any functions for those classes.
Ada
Ada 2005 has added interfaces, allowing a limited form of multiple inheritance.
package Multiple_Interfaces is
type Camera is tagged null record;
type Mobile_Phone is limited Interface;
type Camera_Phone is new Camera and Mobile_Phone with null record;
end Multiple_Interfaces;
Aikido
Aikido does not support multiple inheritance, but does allow multiple implementation of interfaces.
interface Camera {
}
interface Mobile_Phone {
}
class Camera_Phone implements Camera, Mobile_Phone {
}
BBC BASIC
INSTALL @lib$+"CLASSLIB"
DIM Camera{TakePicture}
PROC_class(Camera{})
DIM MobilePhone{MakeCall}
PROC_class(MobilePhone{})
DIM CameraPhone{methods}
PROC_inherit(CameraPhone{}, Camera{})
PROC_inherit(CameraPhone{}, MobilePhone{})
PROC_class(CameraPhone{})
C
C simulates Multiple Inheritance via Structures.
typedef struct{
double focalLength;
double resolution;
double memory;
}Camera;
typedef struct{
double balance;
double batteryLevel;
char** contacts;
}Phone;
typedef struct{
Camera cameraSample;
Phone phoneSample;
}CameraPhone;
C#
In C# you may inherit from only one class, but you can inherit from multiple interfaces. Also, in C# it is standard practice to start all interface names with a capital 'I' so I have altered the name of the interface. In the example we inherit from a class and an interface.
interface ICamera {
// ...
}
class MobilePhone {
// ...
}
class CameraPhone: ICamera, MobilePhone {
// ...
}
C++
class Camera
{
// ...
};
class MobilePhone
{
// ...
};
class CameraPhone:
public Camera,
public MobilePhone
{
// ...
};
Clojure
(defprotocol Camera)
(defprotocol MobilePhone)
(deftype CameraPhone []
Camera
MobilePhone)
COBOL
IDENTIFICATION DIVISION.
CLASS-ID. Camera.
*> ...
END CLASS Camera.
IDENTIFICATION DIVISION.
CLASS-ID. Mobile-Phone.
*> ...
END CLASS Mobile-Phone.
IDENTIFICATION DIVISION.
CLASS-ID. Camera-Phone
INHERITS FROM Camera, Mobile-Phone.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
REPOSITORY.
CLASS Camera
CLASS Mobile-Phone.
*> ...
END CLASS Camera-Phone.
Common Lisp
(defclass camera () ())
(defclass mobile-phone () ())
(defclass camera-phone (camera mobile-phone) ())
D
While D does not have multiple base class inheritance, you can inherit from multiple interfaces.
interface Camera {
// member function prototypes and static methods
}
interface MobilePhone {
// member function prototypes and static methods
}
class CameraPhone: Camera, MobilePhone {
// member function implementations for Camera,
// MobilePhone, and CameraPhone
}
D also supports the non-virtual interface pattern, where an interface may have non-virtual methods with defined implementations.
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();
}
}
}
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 did.
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());
}
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.
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());
}
Using D's CTFE and reflection capabilities, string mixins can copy the interface of other types, and thus be used for proxies and mocks.
Delphi
Delphi doesn't support multiple inheritance, but it does have multiple interfaces.
type
ICamera = Interface
// ICamera methods...
end;
IMobilePhone = Interface
// IMobilePhone methods...
end;
TCameraPhone = class(TInterfacedObject, ICamera, IMobilePhone)
// ICamera and IMobilePhone methods...
end;
DWScript
See Delphi.
E
E does not have multiple inheritance as a built-in feature. In fact, E only has inheritance at all as a light syntactic sugar over delegation (message forwarding). However, using that facility it is possible to implement multiple inheritance.
This is a quick simple implementation of multiple inheritance. It simply searches (depth-first and inefficiently) the inheritance tree for a method; it does not do anything about diamond inheritance. These shortcomings could be fixed if more powerful multiple inheritance were needed.
def minherit(self, supers) {
def forwarder match [verb, args] {
escape __return {
if (verb == "__respondsTo") {
def [verb, arity] := args
for super ? (super.__respondsTo(verb, arity)) in supers {
return true
}
return false
} else if (verb == "__getAllegedType") {
# XXX not a complete implementation
return supers[0].__getAllegedType()
} else {
def arity := args.size()
for super ? (super.__respondsTo(verb, arity)) in supers {
return E.call(super, verb, args)
}
throw(`No parent of $self responds to $verb/$arity`)
}
}
}
return forwarder
}
The task example:
def makeCamera(self) {
return def camera extends minherit(self, []) {
to takesPictures() { return true }
}
}
def makeMobilePhone(self) {
return def mobilePhone extends minherit(self, []) {
to makesCalls() { return true }
to internalMemory() { return 64*1024 }
}
}
def makeCameraPhone(self) {
return def cameraPhone extends minherit(self, [
makeCamera(self),
makeMobilePhone(self),
]) {
to internalMemory() {
return super.internalMemory() + 32 * 1024**2
}
}
}
And testing that it works as intended:
? def p := makeCameraPhone(p)
> [p.takesPictures(), p.makesCalls(), p.internalMemory()]
# value: [true, true, 33619968]
Eiffel
Having two class—one for CAMERA and the other for a MOBILE_PHONE ...
class
CAMERA
end
class
MOBILE_PHONE
end
Now Multiple Inherit
We can create a new CAMERA_PHONE, which inherits directly from both CAMERA and MOBILE_PHONE.
class
CAMERA_PHONE
inherit
CAMERA
MOBILE_PHONE
end
NOTE: There is no reasonable limit to the number of classes we can inherit from in a single class. The compiler helps us to navigate issues like repeated inheritance and the "diamond of death" easily and quickly.
Elena
ELENA only permits inheritance from one parent class. However, mixins are supported
singleton CameraFeature
{
cameraMsg
= "camera";
}
class MobilePhone
{
mobileMsg
= "phone";
}
class CameraPhone : MobilePhone
{
dispatch() => CameraFeature;
}
public program()
{
var cp := new CameraPhone();
console.writeLine(cp.cameraMsg);
console.writeLine(cp.mobileMsg)
}
Alternatively a group object may be created
import system'dynamic;
class CameraFeature
{
cameraMsg
= "camera";
}
class MobilePhone
{
mobileMsg
= "phone";
}
singleton CameraPhone
{
new() = new MobilePhone().mixInto(new CameraFeature());
}
public program()
{
var cp := CameraPhone.new();
console.writeLine(cp.cameraMsg);
console.writeLine(cp.mobileMsg)
}
F#
A class can only inherit from one other class, but it can implement any number of interfaces.
type Picture = System.Drawing.Bitmap // (a type synonym)
// an interface type
type Camera =
abstract takePicture : unit -> Picture
// an interface that inherits multiple interfaces
type Camera2 =
inherits System.ComponentModel.INotifyPropertyChanged
inherits Camera
// a class with an abstract method with a default implementation
// (usually called a virtual method)
type MobilePhone() =
abstract makeCall : int[] -> unit
default x.makeCall(number) = () // empty impl
// a class that inherits from another class and implements an interface
type CameraPhone() =
inherit MobilePhone()
interface Camera with
member x.takePicture() = new Picture(10, 10)
Factor
TUPLE: camera ;
TUPLE: mobile-phone ;
UNION: camera-phone camera mobile-phone ;
Fantom
Fantom only permits inheritance from one parent class. However, Fantom supports 'mixins': a mixin is a collection of implemented methods to be added to the child class. Any number of mixins can be added to any given child class. It is an error for method names to conflict.
// a regular class
class Camera
{
Str cameraMsg ()
{
"camera"
}
}
// a mixin can only contain methods
mixin MobilePhone
{
Str mobileMsg ()
{
"mobile phone"
}
}
// class inherits from Camera, and mixes in the methods from MobilePhone
class CameraPhone : Camera, MobilePhone
{
}
class Main
{
public static Void main ()
{
cp := CameraPhone ()
echo (cp.cameraMsg)
echo (cp.mobileMsg)
}
}
Forth
Standard Forth does not supply high level data structures or functions. But there is library code written by vendors or users. For object programming with multiple inheritance there is a user-supplied ANS compatible extension.
https://github.com/DouglasBHoffman/FMS2 Download the FMSMI package to run the following example code.
\ define class camera with method say:
:class camera
:m say: ." camera " ;m
;class
\ define class phone with method say:
:class phone
:m say: ." phone " ;m
;class
\ define cameraPhone phone with method say:
\ class cameraPhone inherits from both class
\ camera and class phone
:class cameraPhone super{ camera phone }
:m say: self say: \ method conflicts in superclasses
\ are resolved by left-to-right order
\ so self say: will call the say: method
\ from class camera
super> phone say: \ super> phone is used to direct
\ this say: method to use the
\ method from class phone
;m
;class
cameraPhone cp \ instantiate a cameraPhone object named cp
cp say: \ send the say: message to cp
\ output:
camera phone
FreeBASIC
' FB 1.05.0 Win64
' FB does not currently support multiple inheritance. Composition has to be used instead if one wants
' to (effectively) inherit from more than one class. In some cases, this might arguably be a better
' solution anyway.
Type Camera Extends Object ' if virtual methods etc needed
' ...
End Type
Type Phone Extends Object
' ...
End Type
Type CameraPhone Extends Phone ' single inheritance
cam As Camera ' using composition here
' other stuff
End Type
Go
Go abandons traditional object oriented concepts of inheritance hierarchies, yet it does have features for composing both structs and interfaces.
// Example of composition of anonymous structs
package main
import "fmt"
// Two ordinary structs
type camera struct {
optics, sensor string
}
type mobilePhone struct {
sim, firmware string
}
// Fields are anonymous because only the type is listed.
// Also called an embedded field.
type cameraPhone struct {
camera
mobilePhone
}
func main() {
// Struct literals must still reflect the nested structure
htc := cameraPhone{camera{optics: "zoom"}, mobilePhone{firmware: "3.14"}}
// But fields of anonymous structs can be referenced without qualification.
// This provides some effect of the two parent structs being merged, as
// with multiple inheritance in some other programming languages.
htc.sim = "XYZ"
fmt.Println(htc)
}
- Output:
(Note sensor field still blank)
{{zoom } {XYZ 3.14}}
// Example of composition of interfaces.
// Types implement interfaces simply by implementing functions.
// The type does not explicitly declare the interfaces it implements.
package main
import "fmt"
// Two interfaces.
type camera interface {
photo()
}
type mobilePhone interface {
call()
}
// Compose interfaces. cameraPhone interface now contains whatever
// methods are in camera and mobilePhone.
type cameraPhone interface {
camera
mobilePhone
}
// User defined type.
type htc int
// Once the htc type has this method defined on it, it automatically satisfies
// the camera interface.
func (htc) photo() {
fmt.Println("snap")
}
// And then with this additional method defined, it now satisfies both the
// mobilePhone and cameraPhone interfaces.
func (htc) call() {
fmt.Println("omg!")
}
func main() {
// type of i is the composed interface. The assignment only compiles
// because static type htc satisfies the interface cameraPhone.
var i cameraPhone = new(htc)
// interface functions can be called without reference to the
// underlying type.
i.photo()
i.call()
}
- Output:
snap omg!
Groovy
Same inheritance rules as Java.
Haskell
class Camera a
class MobilePhone a
class (Camera a, MobilePhone a) => CameraPhone a
Icon and Unicon
Icon does not support classes or inheritance. An intermediate language called Idol was developed as proof of concept for extending Icon. This became one of the major addons contributing to Unicon.
class Camera (instanceVars)
# methods...
# initializer...
end
class Phone (instanceVars)
# methods...
# initializer...
end
class CameraPhone : Camera, Phone (instanceVars)
# methods...
# initialiser...
end
Io
Camera := Object clone
Camera click := method("Taking snapshot" println)
MobilePhone := Object clone
MobilePhone call := method("Calling home" println)
CameraPhone := Camera clone
CameraPhone appendProto(MobilePhone)
myPhone := CameraPhone clone
myPhone click // --> "Taking snapshot"
myPhone call // --> "Calling home"
In Io each object has an internal list of prototype objects it inherits from. You can add to this list with appendProto
.
Ioke
Camera = Origin mimic
MobilePhone = Origin mimic
CameraPhone = Camera mimic mimic!(MobilePhone)
J
coclass 'Camera'
create=: verb define
NB. creation-specifics for a camera go here
)
destroy=: codestroy
NB. additional camera methods go here
coclass 'MobilePhone'
create=: verb define
NB. creation-specifics for a mobile phone go here
)
destroy=: codestroy
NB. additional phone methods go here
coclass 'CameraPhone'
coinsert 'Camera MobilePhone'
create=: verb define
create_Camera_ f. y
create_MobilePhone_ f. y
NB. creation details specific to a camera phone go here
)
destroy=: codestroy
NB. additional camera-phone methods go here
The adverb Fix (f.) is needed as shown so the superclass constructors get executed in the object, not in the superclass.
Java
Java does not allow multiple inheritance, but you can "implement" multiple interfaces. All methods in interfaces are abstract (they don't have an implementation). When you implement an interface you need to implement the specified methods.
public interface Camera{
//functions here with no definition...
//ex:
//public void takePicture();
}
public interface MobilePhone{
//functions here with no definition...
//ex:
//public void makeCall();
}
public class CameraPhone implements Camera, MobilePhone{
//functions here...
}
Julia
Julia supports inheritance via abstract types. In Julia, multiple dispatch allows objects of different types to have the same function interfaces. Julia also can support traits via parameters in type declarations or with macros. This makes multiple inheritance in Julia mostly unnecessary, except for the inconvenience of composing the data in a mixed type when declaring multiple similar types, for which there are macros.
For example, the functions dialnumber(equipment, name)
and video(equipment, filename)
could be used as generic interfaces to implement methods for a Telephone
, a Camera
, and a SmartPhone
, and Julia would dispatch according to the type of the equipment.
abstract type Phone end
struct DeskPhone <: Phone
book::Dict{String,String}
end
abstract type Camera end
struct kodak
roll::Vector{Array{Int32,2}}
end
struct CellPhone <: Phone
book::Dict{String,String}
roll::Vector{AbstractVector}
end
function dialnumber(phone::CellPhone)
println("beep beep")
end
function dialnumber(phone::Phone)
println("tat tat tat tat")
end
function snap(camera, img)
println("click")
push!(camera.roll, img)
end
dphone = DeskPhone(Dict(["information" => "411"]))
cphone = CellPhone(Dict(["emergency" => "911"]), [[]])
dialnumber(dphone)
dialnumber(cphone)
- Output:
tat tat tat tat beep beep
Kotlin
Interfaces in Kotlin are very similar to Java 8. They can contain declarations of abstract methods, as well as method implementations.
What makes them different from abstract classes is that interfaces cannot store state. They can have properties but these need
to be abstract or to provide accessor implementations.
interface Camera {
val numberOfLenses : Int
}
interface MobilePhone {
fun charge(n : Int) {
if (n >= 0)
battery_level = (battery_level + n).coerceAtMost(100)
}
var battery_level : Int
}
data class CameraPhone(override val numberOfLenses : Int = 1, override var battery_level: Int) : Camera, MobilePhone
data class TwinLensCamera(override val numberOfLenses : Int = 2) : Camera
fun main(args: Array<String>) {
val c = CameraPhone(1, 50)
println(c)
c.charge(35)
println(c)
c.charge(78)
println(c)
println(listOf(c.javaClass.superclass) + c.javaClass.interfaces)
val c2 = TwinLensCamera()
println(c2)
println(listOf(c2.javaClass.superclass) + c2.javaClass.interfaces)
}
- Output:
CameraPhone(numberOfLenses=1, battery_level=50) CameraPhone(numberOfLenses=1, battery_level=85) CameraPhone(numberOfLenses=1, battery_level=100) [class java.lang.Object, interface multiple_inheritance.Camera, interface multiple_inheritance.MobilePhone] TwinLensCamera(numberOfLenses=2) [class java.lang.Object, interface multiple_inheritance.Camera]
Lasso
Lasso only allow single inheritance. But it supports the use of multiple traits and trays hand down the methods it has implemented provided that the type fulfills the requirements for the trait. http://lassoguide.com/language/traits.html
define trait_camera => trait {
require zoomfactor
provide has_zoom() => {
return .zoomfactor > 0
}
}
define trait_mobilephone => trait {
require brand
provide is_smart() => {
return .brand == 'Apple'
}
}
define cameraphone => type {
trait {
import trait_camera, trait_mobilephone
}
data public zoomfactor::integer = 0,
public brand::string
}
local(mydevice = cameraphone)
#mydevice -> brand = 'Apple'
#mydevice -> zoomfactor = 0
#mydevice -> has_zoom
'<br />'
#mydevice -> is_smart
-> false
true
Latitude
Latitude is a prototype-oriented language, and every object can have only one prototype. As such, multiple inheritance in the usual sense is impossible in Latitude. The behavior of multiple (implementation) inheritance can be approximated with mixins.
Camera ::= Mixin clone.
MobilePhone ::= Mixin clone.
CameraPhone ::= Object clone.
Camera inject: CameraPhone.
MobilePhone inject: CameraPhone.
In order to add functionality to either of the mixins, the interface
slot of the mixin must be modified to include the name of the new method. Injecting a mixin makes a copy of the methods, as opposed to traditional (prototype) inheritance in which method calls are delegated.
Lingo
Lingo does not support multiple inheritance. But its slightly idiosyncratic inheritance implementation based on "ancestors" allows to assign/change inheritance relations at runtime. So a similar (but not identical) effect can be achieved by something like this:
-- parent script "Camera"
property resolution
on new (me)
me.resolution = "1024x768"
return me
end
on snap (me)
put "SNAP!"
end
-- parent script "MobilePhone"
property ringtone
on new (me)
me.ringtone = "Bell"
return me
end
on ring (me, n)
repeat with i = 1 to n
put "RING!!!"
end repeat
end
-- parent script "CameraPhone"
property ancestor
on new (me)
c = script("Camera").new()
mp = script("MobilePhone").new()
-- make the Camera instance a parent of the MobilePhone instance
mp.setProp(#ancestor, c)
-- make the MobilePhone instance a parent of this CameraPhone instance
me.ancestor = mp
return me
end
Usage:
cp = script("CameraPhone").new()
cp.snap()
-- "SNAP!"
cp.ring(3)
-- "RING!!!"
-- "RING!!!"
-- "RING!!!"
put cp.resolution
-- "1024x768"
put cp.ringtone
-- "Bell"
Logtalk
Logtalk supports multiple inheritance. There is no "class" keyword in Logtalk; an "object" keyword is used instead (Logtalk objects play the role of classes, meta-classes, instances, or prototypes depending on the relations with other objects).
:- object(camera,
...).
...
:- end_object.
:- object(mobile_phone,
...).
...
:- end_object.
:- object(camera_phone,
specializes(camera, mobile_phone),
...).
...
:- end_object.
Lua
Lua is prototype-based. A table cannot have more than one metatable, but it can reference more than one in its __index metamethod, by making it a closure.
function setmetatables(t,mts) --takes a table and a list of metatables
return setmetatable(t,{__index = function(self, k)
--collisions are resolved in this implementation by simply taking the first one that comes along.
for i, mt in ipairs(mts) do
local member = mt[k]
if member then return member end
end
end})
end
camera = {}
mobilephone = {}
cameraphone = setemetatables({},{camera,mobilephone})
M2000 Interpreter
Module CheckIt {
Class Camera {
Private:
cameratype$
Class:
module Camera (.cameratype$){
}
}
\\ INHERITANCE AT CODE LEVEL
Class MobilePhone {
Private:
model$
Class:
module MobilePhone (.model$) {
}
}
Class CameraPhone as Camera as MobilePhone {
Module CameraPhone ( .model$, .cameratype$) {
}
}
CP1 =CameraPhone("X-15", "OBSCURE")
Print CP1 is type CameraPhone = true
Print CP1 is type Camera = true
Print CP1 is type MobilePhone = true
\\ INHERITANCE AT OBJECT LEVEL
CP2 = MobilePhone("X-9") with Camera("WIDE")
\\ CP3 has no type
Group CP3 {
Module PrintAll {
If this is type Camera and this is type MobilePhone then
Print .model$, .cameratype$
Else
Print "Nothing to print"
End if
}
}
CP3.PrintAll ' Nothing to print
\\ using pointers and prepate inheritance at object level
CP->(CP1 with CP3)
CP=>PrintAll
CP->(CP2 with CP3)
CP=>PrintAll
}
CheckIt
Nemerle
Like C#, Nemerle only allows pseudo-multiple inheritance through interfaces. In Nemerle, the base class must be listed before any interfaces.
interface ICamera {
// ...
}
class MobilePhone {
// ...
}
class CameraPhone: MobilePhone, ICamera {
// ...
}
NetRexx
Like Java, NetRexx doesn't allow true multiple inheritance but instead restricts that capability to interfaces. NetRexx permits the implementation of multiple interfaces. All methods in interfaces are implicitly abstract, thus when you implement an interface you must implement its specified methods.
In this sample the class/interface names are augmented over those required in the task to prevent namespace pollution. The sample also provides a complete working implementation to demonstrate the capability.
/* NetRexx */
options replace format comments java crossref symbols binary
class RInheritMultiple public
method main(args = String[]) public static
iPhone = RInheritMultiple_CameraPhone()
if iPhone <= RInheritMultiple_Camera then -
say -
'Object' hashToString(iPhone) '['iPhone.getClass().getSimpleName()']' -
'is a' RInheritMultiple_Camera.class.getSimpleName()
if iPhone <= RInheritMultiple_MobilePhone then -
say -
'Object' hashToString(iPhone) '['iPhone.getClass().getSimpleName()']' -
'is a' RInheritMultiple_MobilePhone.class.getSimpleName()
say iPhone.snap()
say iPhone.call()
return
method hashToString(that = Object) public static
return '@'(Rexx that.hashCode()).d2x().right(8, 0)
class RInheritMultiple_Camera private interface
-- properties follow...
shutter = 'click...'
-- method prototypes follow
method snap() public returns Rexx
class RInheritMultiple_MobilePhone private interface
-- properties follow...
ringTone = 'ring...'
-- method prototypes follow
method call() public returns Rexx
class RInheritMultiple_CameraPhone private -
implements -
RInheritMultiple_Camera, -
RInheritMultiple_MobilePhone -
uses -
RInheritMultiple_Camera, -
RInheritMultiple_MobilePhone
method RInheritMultiple_CameraPhone() public
return
-- method implementations follow
method snap() public
return shutter
method call() public
return ringTone
- Output:
Object @7F546C85 [RInheritMultiple_CameraPhone] is a RInheritMultiple_Camera Object @7F546C85 [RInheritMultiple_CameraPhone] is a RInheritMultiple_MobilePhone click... ring...
Nim
nim does not support multiple inheritance (version<=1.4.6). It is just a demonstration of the procedure reloading nature of nim code.
type
Camera = ref object of RootObj
MobilePhone = ref object of RootObj
CameraPhone = object
camera: Camera
phone: MobilePhone
proc `is`(cp: CameraPhone, t: typedesc): bool =
for field in cp.fields():
if field of t:
return true
var cp: CameraPhone
echo(cp is Camera)
echo(cp is MobilePhone)
- Output:
true true
Objective-C
Like Java, Objective-C does not allow multiple inheritance, but a class can "conform to" multiple protocols. All methods in protocols are abstract (they don't have an implementation). When you conform to a protocol you need to implement the specified methods.
If you simply want to combine the functionality (method implementations) of multiple classes, you can use message forwarding to mimic the functionality of those classes without actually inheriting them, as described in this guide:
@interface Camera : NSObject {
}
@end
@implementation Camera
@end
@interface MobilePhone : NSObject {
}
@end
@implementation MobilePhone
@end
@interface CameraPhone : NSObject {
Camera *camera;
MobilePhone *phone;
}
@end
@implementation CameraPhone
-(instancetype)init {
if ((self = [super init])) {
camera = [[Camera alloc] init];
phone = [[MobilePhone alloc] init];
}
return self;
}
-(void)forwardInvocation:(NSInvocation *)anInvocation {
SEL aSelector = [anInvocation selector];
if ([camera respondsToSelector:aSelector])
[anInvocation invokeWithTarget:camera];
else if ([phone respondsToSelector:aSelector])
[anInvocation invokeWithTarget:phone];
else
[self doesNotRecognizeSelector:aSelector];
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [camera methodSignatureForSelector:aSelector]
?: [phone methodSignatureForSelector:aSelector]
?: [super methodSignatureForSelector:aSelector];
}
-(BOOL)respondsToSelector:(SEL)aSelector {
return [camera respondsToSelector:aSelector]
|| [phone respondsToSelector:aSelector]
|| [super respondsToSelector:aSelector];
}
@end
Caveat: the CameraPhone class will still technically not inherit from
either the Camera or MobilePhone classes, so testing a CameraPhone object with -isKindOfClass:
with the Camera or MobilePhone classes will still fail.
OCaml
class camera =
object (self)
(*functions go here...*)
end
class mobile_phone =
object (self)
(*functions go here...*)
end
class camera_phone =
object (self)
inherit camera
inherit mobile_phone
(*functions go here...*)
end
Oforth
Oforth does not implement multiple inheritance. It allows only one parent class.
Oforth implements properties (like Comparable, Indexable, ...). A property can have attributes and methods. A class can have multiple properties.
If Camera and MobilePhone are designed as properties, we can write :
Property new: Camera
Property new: MobilePhone
Object Class new: CameraPhone
CameraPhone is: Camera
CameraPhone is: MobilePhone
ooRexx
ooRexx classes have a single superclass and can inherit from multiple mixins. Mixins are more than just interfaces. They can contain concrete method implementations and also create instance variables (scoped as private variables to the mixin methods).
-- inherited classes must be created as mixinclasses.
::class phone mixinclass object
::class camera mixinclass object
-- not a direct subclass of either, but inherits both
::class cameraphone inherit phone camera
-- could also be
::class cameraphone1 subclass phone inherit camera
-- or
::class cameraphone2 subclass camera inherit phone
OxygenBasic
class Camera
string cbuf
method TakePhoto()
end method
method ViewPhoto()
end method
end class
class MobilePhone
string pbuf
method MakeCall()
end method
method TakeCall()
end method
end class
class CameraPhone
has Camera,MobilePhone
end class
CameraPhone cp
cp.ViewPhoto
cp.MakeCall
Oz
class Camera end
class MobilePhone end
class CameraPhone from Camera MobilePhone end
Pascal
See Delphi
PascalABC.NET
In PascalABC.NET you may inherit from only one class, but you can inherit from multiple interfaces.
type
IMy1 = interface
procedure My1;
end;
IMy2 = interface
procedure My2;
end;
MyClass = class(IMy1,IMy2)
public
procedure My1 := Writeln('My1');
procedure My2 := Writeln('My2');
end;
MyClassD = class(MyClass,IMy1,IMy2)
end;
begin
var my := new MyClassD;
my.My1; my.My2;
end.
Perl
package Camera;
#functions go here...
1;
package MobilePhone;
#functions go here...
1;
package CameraPhone;
use Camera;
use MobilePhone;
@ISA = qw( Camera MobilePhone );
#functions go here...
1;
or
package CameraPhone;
use base qw/Camera MobilePhone/;
#functions go here...
The same using the MooseX::Declare extention:
use MooseX::Declare;
class Camera {
# methods ...
}
class MobilePhone {
# methods ...
}
class CameraPhone extends(Camera, MobilePhone) {
# methods ...
}
Phix
Needs 0.8.1+
inheritance
The programmer is expected to assume complete responsibility (away from the compiler) for checking/resolving any conflicts.
class Camra
string name = "nikkon"
end class
class Mobile
-- string name = "nokia" -- oops!
string mane = "nokia" -- ok!
end class
class CamraPhone extends Camra,Mobile
procedure show() ?{name,mane} end procedure
end class
CamraPhone cp = new()
cp.show()
- Output:
{"nikkon","nokia"}
composition
The programmer is expected to assume complete responsibility for invoking new() appropriately.
The example below shows four different approaches to invoking all the new() that are needed (one pair commented out).
Note that invoking new() inside a class definition creates shared references to a single instance.
The compiler demands to be explicitly told what the inner/inlined new() on cp2 are actually for.
class Camera
public string name = "nikkon"
end class
class MobilePhone
public string name = "nokia" -- (clash no more)
end class
class CameraPhone
-- Camera c = new()
-- MobilePhone m = new()
public Camera c
public MobilePhone m
procedure show() ?{c.name,m.name} end procedure
end class
Camera c = new({"canon"})
MobilePhone m = new()
CameraPhone cp1 = new({c,m}),
cp2 = new({new("Camera"),new("MobilePhone")}),
cp3 = new() -- (internal/shared/NULL c,m)
cp3.c = new() -- (obviously c must be public)
cp3.m = new({"LG20"}) -- "" m "" ""
cp1.show()
cp2.show()
cp3.show() -- crashes without internal/above new()
- Output:
{"canon","nokia"} {"nikkon","nokia"} {"nikkon","LG20"}
PicoLisp
(class +Camera)
(class +MobilePhone)
(class +CameraPhone +MobilePhone +Camera)
Pop11
;;; load object support
lib objectclass;
define :class Camera;
;;; slots go here
enddefine;
define :class MobilePhone;
;;; slots go here
enddefine;
define :class CameraPhone is Camera, MobilePhone;
;;; extra slots go here
enddefine;
;;; methods go here
PowerShell
class Camera {}
class MobilePhone {}
class CameraPhone : Camera, MobilePhone {}
PureBasic
Using the open-source precompiler SimpleOOP.
Class Camera
EndClass
Class Mobil
EndClass
Class CameraMobile Extends Camera Extends Mobil
EndClass
Python
class Camera:
pass #functions go here...
class MobilePhone:
pass #functions go here...
class CameraPhone(Camera, MobilePhone):
pass #functions go here...
Racket
Racket allows multiple inheritance with interfaces, but not classes. Mixins can be used to achieve some of the benefits of multiple inheritance.
#lang racket
(define camera<%> (interface ()))
(define mobile-phone<%> (interface ()))
(define camera-phone%
(class* object% (camera<%> mobile-phone<%>)
(super-new)
;; implement methods here
))
Raku
(formerly Perl 6)
class Camera {}
class MobilePhone {}
class CameraPhone is Camera is MobilePhone {}
say CameraPhone.^mro; # undefined type object
say CameraPhone.new.^mro; # instantiated object
- Output:
CameraPhone() Camera() MobilePhone() Any() Mu() CameraPhone() Camera() MobilePhone() Any() Mu()
The .^mro is not an ordinary method call, but a call to the object's metaobject that returns the method resolution order for this type.
Ring
# Project : Inheritance/Multiple
mergemethods(:CameraPhone,:MobilePhone)
o1 = new CameraPhone
? o1
? o1.testCamera()
? o1.testMobilePhone()
func AddParentClassAttributes oObject,cClass
# Add Attributes
cCode = "oTempObject = new " + cClass
eval(cCode)
for cAttribute in Attributes(oTempObject)
AddAttribute(oObject,cAttribute)
cCode = "oObject." + cAttribute + " = oTempObject." + cAttribute
eval(cCode)
next
class Camera
Name = "Camera"
func testCamera
? "Message from testCamera"
class MobilePhone
Type = "Android"
func testMobilePhone
? "Message from MobilePhone"
class CameraPhone from Camera
# Add MobilePhone Attributes
AddParentClassAttributes(self,:MobilePhone)
Output:
name: Camera type: Android Message from testCamera Message from MobilePhone
Ruby
Ruby does not have multiple inheritance, but you can mix modules into classes:
module Camera
# define methods here
end
class MobilePhone
# define methods here
end
class CameraPhone < MobilePhone
include Camera
# define methods here
end
Rust
trait Camera {}
trait MobilePhone {}
trait CameraPhone: Camera + MobilePhone {}
Scala
trait Camera
trait MobilePhone
class CameraPhone extends Camera with MobilePhone
Self
Self is a class-free, object-oriented language, and as such, it uses prototypal inheritance instead of classical inheritance. This is an example of the relevant excerpts from a Self transporter fileout. Normally the object tree would be built and navigated within the graphical Self environment.
camera = ()
mobilePhone = ()
cameraPhone = (| cameraParent* = camera. mobilePhoneParent* = mobilePhone |)
Sidef
class Camera {};
class MobilePhone {};
class CameraPhone << Camera, MobilePhone {};
Slate
define: #Camera.
define: #MobilePhone.
define: #CameraPhone &parents: {Camera. MobilePhone}.
Swift
Like Objective-C, Swift does not allow multiple inheritance. However, you can conform to multiple protocols.
protocol Camera {
}
protocol Phone {
}
class CameraPhone: Camera, Phone {
}
Tcl
or
package require TclOO
oo::class create Camera
oo::class create MobilePhone
oo::class create CameraPhone {
superclass Camera MobilePhone
}
Wren
Wren does not support either multiple inheritance or interfaces.
However, multiple inheritance can be simulated by inheriting from a single class and then embedding objects of other classes and wrapping their methods.
class Camera {
construct new() {}
snap() { System.print("taking a photo") }
}
class Phone {
construct new() {}
call() { System.print("calling home") }
}
class CameraPhone is Camera {
construct new(phone) { _phone = phone } // uses composition for the Phone part
// inherits Camera's snap() method
// Phone's call() method can be wrapped
call() { _phone.call() }
}
var p = Phone.new()
var cp = CameraPhone.new(p)
cp.snap()
cp.call()
- Output:
taking a photo calling home
zkl
class Camera{} class MobilePhone{}
class CameraPhone(Camera,MobilePhone){}
CameraPhone.linearizeParents
- Output:
Show the class search order
L(Class(CameraPhone),Class(Camera),Class(MobilePhone))
- Programming Tasks
- Basic language learning
- Object oriented
- Type System
- Ada
- Modula-2/Omit
- Aikido
- BBC BASIC
- C
- C sharp
- C++
- Clojure
- COBOL
- Common Lisp
- D
- Delphi
- DWScript
- E
- Eiffel
- Elena
- F Sharp
- Factor
- Fantom
- Forth
- FreeBASIC
- Go
- Groovy
- Haskell
- Unicon
- Icon/Omit
- Io
- Ioke
- J
- Java
- Julia
- Kotlin
- Lasso
- Latitude
- Lingo
- Logtalk
- Lua
- M2000 Interpreter
- Nemerle
- NetRexx
- Nim
- Objective-C
- OCaml
- Oforth
- OoRexx
- OxygenBasic
- Oz
- Pascal
- PascalABC.NET
- Perl
- Phix
- Phix/Class
- PicoLisp
- Pop11
- PowerShell
- PureBasic
- Python
- Racket
- Raku
- Ring
- Ruby
- Rust
- Scala
- Self
- Sidef
- Slate
- Swift
- Tcl
- TclOO
- Wren
- Zkl
- 6502 Assembly/Omit
- 68000 Assembly/Omit
- 8080 Assembly/Omit
- 8086 Assembly/Omit
- ARM Assembly/Omit
- AWK/Omit
- Axe/Omit
- Batch File/Omit
- JavaScript/Omit
- Metafont/Omit
- Mathematica/Omit
- Maxima/Omit
- MIPS Assembly/Omit
- ML/I/Omit
- PARI/GP/Omit
- Retro/Omit
- TI-83 BASIC/Omit
- TI-89 BASIC/Omit
- Z80 Assembly/Omit