In object-oriented programming, an indexer allows instances of a particular class or struct to be indexed just like arrays. [1] It is a form of operator overloading.
In C++ one can emulate indexing by overloading the []
operator. The expression a[b...]
translates to a call to the user-defined function operator[]
as (a).operator[](b...)
. [2] Here is an example,
structvector{intsize;double*data;vector(intn){size=n;data=newdouble[n]();}~vector(){size=0;delete[]data;}double&operator[](inti){returndata[i];}};#include<iostream>intmain(){vectorv(3);for(inti=0;i<v.size;i++)v[i]=i+1;for(inti=0;i<v.size;i++)std::cout<<v[i]<<"\n";return0;}
Indexers are implemented through the get and set accessors for the operator[]
. They are similar to properties, but differ by not being static, and the fact that indexers' accessors take parameters. The get and set accessors are called as methods using the parameter list of the indexer declaration, but the set accessor still has the implicit value
parameter.
publicclassVector{privatedouble[]_data;publicVector(intn){_data=newdouble[n];}publicintSize=>_data.Length;publicdoublethis[inti]{get=>_data[i];set=>_data[i]=value;}publicstaticvoidMain(){varvector=newVector(3);for(vari=0;i<vector.Size;i++)vector[i]=i+1;for(vari=0;i<vector.Size;i++)System.Console.WriteLine(vector[i]);}}
Here is a C# example of the usage of an indexer in a class: [3]
classFamily{privateList<string>_familyMembers=newList<string>();publicFamily(paramsstring[]members){_familyMembers.AddRange(members);}publicstringthis[intindex]{// The get accessorget=>_familyMembers[index];// The set accessor with set=>_familyMembers[index]=value;}publicintthis[stringval]{// Getting index by value (first element found)get=>_familyMembers.FindIndex(m=>m==val);}publicintLength=>_familyMembers.Count;}
Usage example:
voidMain(){vardoeFamily=newFamily("John","Jane");for(inti=0;i<doeFamily.Length;i++){varmember=doeFamily[i];varindex=doeFamily[member];// same as i in this case, but it demonstrates indexer overloading allowing to search doeFamily by value.Console.WriteLine($"{member} is the member number {index} of the {nameof(doeFamily)}");}}
In this example, the indexer is used to get the value at the nth position, and then to get the position in the list referenced by its value. The output of the code is:
John is the member number 0 of the doeFamily Jane is the member number 1 of the doeFamily
In PHP indexing can be implemented via the predefined ArrayAccess
interface, [4]
classVectorimplementsArrayAccess{function__construct(int$n){$this->size=$n;$this->data=array_fill(0,$n,0);}publicfunctionoffsetGet($offset):mixed{return$this->data[$offset];}publicfunctionoffsetSet($offset,$value):void{$this->data[$offset]=$value;}publicfunctionoffsetExists($offset):bool{}publicfunctionoffsetUnset($offset):void{}}$vector=newVector(3);for($i=0;$i<$vector->size;$i++)$vector[$i]=$i+1;for($i=0;$i<$vector->size;$i++)print"{$vector[$i]}\n";
In Python one implements indexing by overloading the __getitem__
and __setitem__
methods,
importarrayclassVector(object):def__init__(self,n:int):self.size=nself.data=array.array("d",[0.0]*n)def__getitem__(self,i:int):returnself.data[i]def__setitem__(self,i:int,value):self.data[i]=valuevector=Vector(3)foriinrange(vector.size):vector[i]=i+1foriinrange(vector.size):print(vector[i])
Rust provides the std::ops::Index trait. [5]
usestd::ops::Index;enumNucleotide{A,C,G,T,}structNucleotideCount{a: usize,c: usize,g: usize,t: usize,}implIndex<Nucleotide>forNucleotideCount{typeOutput=usize;fnindex(&self,nucleotide: Nucleotide)-> &Self::Output{matchnucleotide{Nucleotide::A=>&self.a,Nucleotide::C=>&self.c,Nucleotide::G=>&self.g,Nucleotide::T=>&self.t,}}}letnucleotide_count=NucleotideCount{a: 14,c: 9,g: 10,t: 12};assert_eq!(nucleotide_count[Nucleotide::A],14);assert_eq!(nucleotide_count[Nucleotide::C],9);assert_eq!(nucleotide_count[Nucleotide::G],10);assert_eq!(nucleotide_count[Nucleotide::T],12);
In Smalltalk one can emulate indexing by (e.g.) defining the get:
and set:value:
instance methods. For example, in GNU Smalltalk,
Objectsubclass:vector [ |data| ] vectorclassextend [ new:n [ |v|v:=supernew.vinit:n.^v] ] vectorextend [ init:n [ data:=Arraynew:n ] ] vectorextend [ size [ ^(datasize) ] ] vectorextend [ get:i [ ^(dataat:i) ] ] vectorextend [ set:ivalue:x [ dataat:iput:x ] ] v:=vectornew:31to: (vsize) do: [:i|vset:ivalue: (i+1) ] 1to: (vsize) do: [:i| (vget:i) printNl ]
{{cite web}}
: CS1 maint: numeric names: authors list (link)