PureBasic
and the Object-Oriented Programming
In this section, I present how the object concepts can be simply implemented
in PureBasic.
This implementation doesn't refer what is programmed in object-oriented
languages. Furthermore, the goal of an implementation is to be improved
or to be adapted to the need.
Thus, I propose here one of these implementations with its own advantages
and limits.
First Implementation
Concrete Class and Abstract
Class
As seen, the Class defines the contents of an object:
- Its attributes (each variable type)
- Its methods (Names, implementation)
For example, if I want to represent Rectangle objects and to display
them on the screen, I shall define a Class Rectangle including a Draw()
method.
The Class Rectangle could have the following construction:
Structure
Rectangle
*Draw
x1.l
x2.l
y1.l
y2.l
EndStructure
Procedure
Draw_Rectangle(*this.Rectangle)
EndProcedure
|
where x1, x2, y1 and y2 are four attributes (diametrically opposite points
coordinates of the rectangle) and *Draw is a pointer referencing to
the drawing function which displays Rectangles.
*Draw is here a function pointer used to contain the address of the wished
function: @Draw_Rectangle().
By using CallFunctionFast(), a such referenced function can be used.
Thus, the proposed Structure is completely adapted to the Class notion:
the structure stores the definition of the object attributes: x1, x2,
y1 and y2 are here Long variables.
the structure stores the definition of the object method: here the Draw()
function thanks to a function pointer.
If a such defined Class is followed by the method implementations (in
our example it is the Draw_Rectangle()
Procedure/EndProcedure block statement), the Class will be a concrete
Class.
In the opposite, the Class will be a abstract Class.
|
*this always refers to the object on which
the method must be applied. This notation is applied in our example
with the method Draw_Rectangle(). |
Instanciation
Now, to create an object called Rect1 from the Rectangle Class, write:
To initialize it, simple write:
Rect1\Draw = @Draw_Rectangle()
Rect1\x1 = 0
Rect1\x2 = 10
Rect1\y1 = 0
Rect1\y2 = 20
|
Next, to draw Rect1 object, do:
CallFunctionFast(Rect1\Draw,
@Rect1)
|
Encapsulation
In this implementation, the encapsulation doesn't exist, simply because
there is no way to hide the attributes or the methods of such an object.
By writing Rect1\x1, the user can access to the attribute x1 of the object.
This way was used to initialize the object.
The next implementation (second
implementation chapter) will show how to fix this.
Although importing, this notion is not the most essential to practice
OOP.
Inheritance
Now I want to create a new Class with the capability to Erase rectangles
from the screen.
I can perform this new Rectangle2 Class by using the existing Rectangle
Class and by providing to it a new method called Erase().
A Class being a Structure, let me take advantage of the extension property
from structure. So, the new Class Rectangle2 can be:
Structure Rectangle2 Extends
Rectangle
*Erase
EndStructure
Procedure Erase_Rectangle(*this.Rectangle2)
EndProcedure
|
The Rectangle2 Class includes as well members of the previous Rectangle
Class and the new Erase() method.
To instanciate an object from this new Class write:
Rect2.Rectangle2
Rect2\Draw = @Draw_Rectangle()
Rect2\Erase = @Erase_Rectangle()
Rect2\x1 = 0
Rect2\x2 = 10
Rect2\y1 = 0
Rect2\y2 = 20
|
To use Draw() and Erase()
methods of Rect2, I shall proceed in the same way as previously: thanks
to CallFunctionFast()
That shows that Rectangle2 Class inherited properties of Rectangle
Class.
|
The inheritance is a category of polymorphism.
The object Rect2 can be seen also as an Object from the Class Rectangle.
For this, just don't use the Erase() method! By inheritance, the
object carries several forms: those of the objects coming from the
Mothers Classes. It is named as polymorphism inheritance . |
Overload
During the initialization of an object, the function pointers are initialized
by assigning to them the method addresses, which are convenient for the
object.
So, for an object Rect from Rectangle Class, by writing:
Rect1\Draw = @Draw_Rectangle()
|
I can use the Draw() method as
following:
CallFunctionFast(Rect1\Draw,
@Rect1)
|
Now, imagine that it is possible to implement another method for a rectangle
display (by using a different algorithm than for the first method).
Let us call this implementation as Draw_Rectangle2():
Procedure Draw_Rectangle2(*this.Rectangle)
EndProcedure
|
It is possible to initialize our object Rect1 with this new method without
effort:
Rect1\Draw = @Draw_Rectangle2()
|
To use the method, write again:
CallFunctionFast(Rect1\Draw,
@Rect1)
|
In a hand (Draw_Rectangle() method)
as in the other hand (Draw_Rectangle2()
method) the use of the Rect1 method is strictly identical.
By the only line " CallFunctionFast (Rect1\Draw, @Rect1) ",
it isn't possible to distinguish the Draw()
method that the Rect1 object really uses.
To know this, it is necessary to go back to the initialization of the
object.
The notion of function pointer allows the overloading of the Draw()
method.
One limitation: the use of the CallFunctionFast() instruction implies
to pay attention among the parameter numbers.
Conclusion:
In this first implementation, an object is able to answer to the main
object-oriented concepts with some limitations.
In fact I have just put the bases for realizing a more complete object,
this thanks to the PureBasic Interface instruction.
[1-2-3-4-5-6-7-8-9]
Top of the page
|