Slicing
A derived object can be passed wherever its base type is wanted. How it is passed decides whether the procedure gets the object or only part of it.
type Animal extends Object
declare virtual function Sound( ) as ustring
legs as int32
end type
function Animal.Sound( ) as ustring
return "..."
end function
type Dog extends Animal
declare function Sound( ) as ustring override
tricks as int32
end type
function Dog.Sound( ) as ustring
return "woof"
end function
sub ByReference( byref a as Animal )
print "byref: "; a.Sound( ); ", a Dog: "; cbool( a is Dog )
end sub
'' byval makes a new Animal from the Animal part of the argument.
sub ByValue( byval a as Animal )
print "byval: "; a.Sound( ); ", a Dog: "; cbool( a is Dog )
end sub
dim as Dog rex
rex.tricks = 3
ByReference( rex )
ByValue( rex )
'' Assignment to an Animal does the same.
dim as Animal pet = rex
print "copied: "; pet.Sound( ); ", a Dog: "; cbool( pet is Dog )
'' A pointer keeps the whole object.
dim as Animal ptr p = @rex
print "ptr: "; p->Sound( ); ", a Dog: "; cbool( *p is Dog )
'' The hidden table pointer is the whole of an Object.
print "sizes:"; sizeof( Object ); sizeof( Animal ); sizeof( Dog )
Output
byref: woof, a Dog: true
byval: ..., a Dog: false
copied: ..., a Dog: false
ptr: woof, a Dog: true
sizes: 8 16 24
ByReference receives rex itself, so the virtual call reaches Dog.Sound
and is Dog is true.
ByValue receives a new Animal, built by copying the Animal part of
rex. That copy is an Animal through and through: it says ..., it is not
a Dog, and tricks is not part of it at all. The derived part has been
sliced off. Assigning a Dog to an Animal variable does the same. A
pointer, like a byref parameter, refers to the whole object.
The last line shows the hidden field behind all of this. Object is 8
bytes: the pointer to the type's table of virtual methods, and nothing else.
Animal adds legs and rounds up to 16, and Dog adds tricks and rounds
up to 24.
Nothing warns about slicing, because from the compiler's side nothing is
wrong: an Animal was asked for and an Animal was made. Pass objects of a
type with virtual methods byref or by pointer, never byval, and keep
them in Animal ptr variables rather than Animal ones.
Activities
- Change
ByValueto take its parameterbyrefand compare the output. - Put
rexin adim as Animal pets( 0 to 0 )array and callSoundon the element. Then try an array ofAnimal ptr.