Classes

Just starting out? Need help? Post your questions and find answers here.
mbecerra
User
User
Posts: 15
Joined: Mon Feb 28, 2005 4:59 am

Classes

Post by mbecerra »

Is it possible to do "classes" in PB similar to C++? That is:

Code: Select all

Class Paddle {
Private:
x_position;
y_position;

public:
set_x_position(new_x_position);
set_y_position(new_y_position);

}
Then somewhere else in another file or another part of the source code:

Code: Select all

Paddle::set_x_position(new_x_position){
x_position = new_x_position;
}

Paddle::set_y_position(new_y_position){
y_position = new_y_position;
}

Usage:

Code: Select all

Paddle Player1

player1.set_x_position(320);
player1.set_y_position(240);

Paddle Player2

player2.set_x_position(320);
player2.set_y_position(240);
Is this possible already or do i need to add it to the wishlist?
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Post by Kale »

Not conventionally but it is possible to simulate them:

http://www.purebasic.fr/english/viewtopic.php?t=19416
--Kale

Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

This is accomplished in PureBasic using interfaces. Here's a tiny demo to show the approach using your example:

Code: Select all

;======================================================== 
; Program:           Simple Classes in PureBasic 
; Author:            netmaestro 
; Date:              August 7, 2006 
; Target OS:         Windows all 
; Target Compiler:   PureBasic 4.0 or higher 
;======================================================== 

; ================================== 
; Begin Class Definition: Paddle 
; Contents: 
;   1. Structure 
;   2. Interface 
;   3. Methods 
;   4. VTable 
;=================================== 

Structure Paddle 
  VTable.l 
  x.l 
  y.l 
EndStructure 

Interface Paddle_Objects 
  MoveTo(x,y)
  GetX() 
  GetY() 
EndInterface 

Procedure.l NewObject_Paddle() 
  Protected *newobject.Paddle 
  *newobject = AllocateMemory(SizeOf(Paddle)) 
  *newobject\VTable = ?Paddle_VTable 
  ProcedureReturn *newobject 
EndProcedure 

Procedure MoveTo(*Self.Paddle, x, y) 
  *Self\x = x 
  *Self\y = y 
EndProcedure 

Procedure GetX(*Self.Paddle) 
  ProcedureReturn *Self\x 
EndProcedure 

Procedure GetY(*Self.Paddle) 
  ProcedureReturn *Self\y 
EndProcedure 

DataSection 
  Paddle_VTable: 
  Data.l @MoveTo(), @GetX(), @GetY() 
EndDataSection 

;==================================== 
;    End of Class Definition 
;==================================== 

; simple test program to demonstrate using the Paddle class 

Paddle1.Paddle_Objects = NewObject_Paddle() 
Paddle2.Paddle_Objects = NewObject_Paddle() 

Paddle1\MoveTo(5,6)
Paddle2\MoveTo(7,8)

; Display object properties using Get methods 

Debug Paddle1\GetX() 
Debug Paddle1\GetY() 
Debug Paddle2\GetX() 
Debug Paddle2\GetY() 

End 
Most objects are much more complex than this of course, but there's enough here to show the process.
BERESHEIT
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

Here the readme of my preprocessor:

Code: Select all

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                     
                                 LCP - Little Class preprocessor       
                                     
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            OOP preprocessor - by FSW - Version 0.7 - August 2006
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 This software is called Little Class Preprocessor because it is a little class
 preprocessor.
 It is not the intention of this piece of software to turn PureBasic into a full blown
 OOP language.
 If you need a full blown OOP language use C++/Eiffel/Java etc.

 You can already create Objects with PureBasic with the help of Structures/Interfaces.

 The intention of this software is to make the creation of Objects in PureBasic easier.
 
 This software helps to keep the coding time small because it does the Class translation
 to Structures/Interfaces for you.
 Now you can fully concentrate on the task instead of how to use Structures/Interfaces to
 make Objects out of it.

 Include files can be used. This preprocessor uses all files and compiles them into one.
 This is needed for class inheritance. Now you can have your classes nicely packaged into
 different files. Just include them and the inheritance works.

 The next step would be to create a program/procedure that would delete all unused class
 properties and methods to decrease the program size.
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 The preprocessor takes a Class Declaration and translates into:

 1.) Create a Structure for the Properties (Variables)
 2.) Create a Interface for the Methods (Procedures)
 3.) Declare the Methods 
 4.) Create a DataSection for the needed Virtual Table
 5.) Glue all together and make it work

 6.) Takes the Object creation and translates it for each possible type of object:
     Variables, Linked Lists and Arrays.
 7.) If assigned, execute the constructor at initialization.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Before you will be introduced to Classes lets talk about Structures (user Types).

 Most Programming languages can hold Variables and Procedures in Structures.

 In PureBasic Strucures can only hold variables. 
 PureBasic has so called Interfaces to handle Procedures. 

 Lets take a look at Structures:

 Structure MyStructure
   MyVar1.l
   MyVar2.s
 EndStructure


 Now lets take a look at Interfaces:

 Interface MyInterface
   MyProc1()
   MyProc2(par.l)
 EndStructure


 Now lets take a look at Classes as they can be defined with this preprocessor:

 Class MyClass
   MyVar1.l
   MyVar2.s
   MyProc1()
   MyProc2(par.l)
 EndClass

 At first sight a class looks like a Structure in other Basic languages, but there is 
 a main difference.
 In other Basic languages the Procedures (called from Structures) need the caller as 
 first parameter when they need to work with the object, while Procedures from a Class
 generated with this preprocessor don't.
 This is because PureBasic's Interfaces are more than a Structure in other Basic
 languages. (for more information look at the PureBasic help file). 
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Lets look again how a Class declaration with this preprocessor looks like:

 ;class declaration
 Class MyClass
   My1stProperty
   My2ndProperty.l
   My1stMethod(par)
   My2ndMethod.s()
 EndClass

 Lets look how a Object creation with this preprocessor looks like, specially look at
 the "NEW" keyword that makes it all possible:

 ;object creation and initialize as variable
 myVar.MyClass = New MyClass
 ;or
 ;object creation and initialize as global variable
 Global myVar.MyClass = New MyClass

 ;or

 ;object creation as variable
 myVar.MyClass
 ;initialize
 myVar = New MyClass
 ;or
 ;object creation as global variable
 Global myVar.MyClass
 ;initialize
 myVar = New MyClass

 ;and work with it with:
 With myVar
   ->My1stMethod(123)
 EndWith       
 myVar->My2ndMethod()


 ;object creation as Linked List
 NewList myList.MyClass()
 ;or
 ;object creation as global Linked List
 Global NewList myList.MyClass()

 ;initialize
 For i = 0 To 5
   AddElement(myList())
   myList() = New MyClass
 Next
  
 ;and work with it with:
 FirstElement(myList())
 For i = 0 To 5
   NextElement(myList())
   With myList()
     ->My1stMethod(i)
   EndWith         
   myList()->My2ndMethod()
 Next


 ;object creation as Array
 Dim myArray.MyClass(5)
 ;or
 Global Dim myArray.MyClass(5)

 ;initialize
 For i = 0 To 5
   myArray(i) = New myClass
 Next
  
 ;and work with it with:
 For i = 0 To 5
   With myArray(i)
     ->My1stMethod(i)
   EndWith         
   myArray(i)->My2ndMethod()
 Next
 
 If there is no type assigned to a property or a return value to a method ".l" (for long)
 will be assigned. Methods that don't have LONG as a return need to be declared with a
 return type like: GetText.s()


 As you can see the object creation looks almost like a normal declaration in PureBasic:
 The only different thing is that the "NEW" keyword is used.
 This keyword helps the preprocessor to find a line to work with. 
 Also as with normal initialization, only when using Variables the object creation and
 init can be done on one line, because with Lists and Arrays the single Elements need to
 be initialized.
 

 The syntax of this preprocessor doesn't want to change PureBasic original syntax or to
 force a OOP syntax that is not in harmony with PureBasic's original syntax.
 As you can see Variable, Linked List and Array creation didn't change at all.
 

 BTW: the class initialization looks like any other OOP language (examples):

 JAVA:      MyClass MyObject = new MyClass();

 C++:       MyClass *MyObject = new MyClass;
 or
 C++:       MyClass *MyObject = new MyClass(1,2);

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                     
 Double Colon for Class Methods:

 Normal Procedures in PureBasic are written as:

 Procedure MyProcedure(FirstParameter)
   ;do something
   MyParameter = 123 * FirstParameter
   ProcedureReturn MyParameter
 EndProcedure


 Class methods are written with "Class name" "::" "Method name" like in other oop
 languages:

 Procedure MyClass::MyMethod()
   ;do something
   *This->MYProperty = 123
 EndProcedure

 As you can see "->" is used to access the object property. And "This" is used for the
 object address pointer.
 Lets look at it again, this is used to access a property inside a method:

 *This->MYProperty = 123

 
 Finally in the program Methods are called this way:

 MyObject->MYMethod()


 As you can see "->" is used. Isn't this nice?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Constructor:

 Since version 0.5 of this preprocessor it is possible to use a constructor. A constructor
 is nothing else than a Method (Procedure) that is called at Object initialization.

 A constructor is defined inside the class and needs always the same name as the class:

 ;class declaration
 Class MyClass
   My1stProperty
   My2ndProperty.l
   MyClass()         ;<- here is the constructor
   My1stMethod(par)
   My2ndMethod.s()
 EndClass


 The Method itself is written as:

 Procedure MyClass::MyClass()
   ;do something
   *This->MYProperty = 123
 EndProcedure


 Lets look at a normal object creation and initialization without a constructor:

 ;object creation and initialize as variable without constructor
 myVar.MyClass = New MyClass


 Now lets look at a object creation and initialization with a constructor:

 ;object creation and initialize as variable with constructor
 myVar.MyClass = New MyClass()


 As you can see the only difference are the parentesis.
 You can pass parameters if you need to, like:

 ;object creation and initialize as variable with constructor and parameters
 myVar.MyClass = New MyClass(par1, par2)

 
 Yes, it's that easy.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Multiple Inheritance:

 Inheritance can be defined through the PureBasic Keyword EXTENDS.

 Class YourClass
   Your1stProperty
   Your2ndProperty.l
   Your1stMethod()
   Your2ndMethod.s()
 EndClass

 Class MyClass Extends YourClass
   My1stProperty
   My2ndProperty.l
   My1stMethod()
   My2ndMethod.s()
 EndClass

 Inheritance works across all files. 
 If a class is in an include file you need to inlude the file prior to the use of it.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Multiple Inheritance and constructors:

 For now the constructor of the actual class will be started automatically, if defined.
 A constructor defined in a inherited class is viewed as a normal method.
 If you need to call it, do it yourself:

 Class YourClass
   Your1stProperty
   Your2ndProperty.l
   Your1stMethod()
   Your2ndMethod.s()
   YourClass()
 EndClass

 Class MyClass Extends YourClass
   My1stProperty
   My2ndProperty.l
   My1stMethod()
   My2ndMethod.s()
 EndClass

 myVar.MyClass = New MyClass    ;<- no constructor
 myVar->YourClass()             ;<- constructor of YourClass is called manually


 You could also have 2 constructors:

 Class YourClass
   Your1stProperty
   Your2ndProperty.l
   Your1stMethod()
   Your2ndMethod.s()
   YourClass()
 EndClass

 Class MyClass Extends YourClass
   My1stProperty
   My2ndProperty.l
   My1stMethod()
   My2ndMethod.s()
   MyClass()
 EndClass

 myVar.MyClass = New MyClass()  ;<- constructor of MyClass is called at initialization
 myVar->YourClass()             ;<- constructor of YourClass is called manually
 
 As you can see the constructor of the actual class is called first.


 You can call the constructor of the inherited class in the constructor of the new class:

 Procedure MyClass::MyClass()
   ;do something
   *This->YourClass()           ;<- constructor of YourClass is called manually
 EndProcedure

 myVar.MyClass = New MyClass()  ;<- constructor of MyClass is called at initialization

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Data Encapsulation:
 
 All Properties are private, they need to be accessed through the Methods.
 They can't be directly accessed through code like this:

 MyObject->MYProperty

 This way the properties can't be manipulated that easy, which is less error phrone.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Keywords:                            
       
 The following keywords should be viewed like PureBasic keywords, use them for the purpose
 they are designed:
                               
 Class                                
 EndClass                             
 New                               
 This                                 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 Included Files:

 For now the commands XIncludeFile and IncludeFile are both treated as IncludeFile.
 This means that when the preprocessor finds XIncludeFile the file is always included.
 There is no mechanism in place that counts how often a certain Include file is already
 included.
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Still working on it, but what is decribed in the readme works pretty good so far.

It's the 3rd rewrite of it, so since version 0.7 it's completely written in itself :shock:
KarLKoX
Enthusiast
Enthusiast
Posts: 681
Joined: Mon Oct 06, 2003 7:13 pm
Location: France
Contact:

Post by KarLKoX »

Image
"Qui baise trop bouffe un poil." P. Desproges

http://karlkox.blogspot.com/
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Besides of the way explained by Netmaestro, you can design you own way (like C++ syntax developed by fsw), or others.
Since i dislike C++ syntax, I like and use this way (example):

Code: Select all

Macro EnableClass(ClassName)
  Global NewList ClassName#.c#ClassName#()
EndMacro
Macro DisableClass(ClassName)
  ;Flush ClassName#.c#ClassName#()  ; <- Pity PB doesn't allow to flush a previously created variable :-|
EndMacro
Macro New_Obj(ObjectName,ClassName); <- Create an object (ObjectName) of the class (ClassName)
  AddElement(ClassName#())
  ClassName#()\VTable=?c#ClassName#_VT
  ObjectName#.i#ClassName#=@ClassName#()
EndMacro
Macro Free_Obj(ObjectName,ClassName); <- Erase an object (ObjectName) of the class (ClassName)
  If ClassName#()=ObjectName
    DeleteElement(ClassName#())
  Else
    PokeL(?c#ClassName#_VT+SizeOf(i#ClassName#),@ClassName#())
    ChangeCurrentElement(ClassName#(),ObjectName#)
    DeleteElement(ClassName#())
    ChangeCurrentElement(ClassName#(),PeekL(?c#ClassName#_VT+SizeOf(i#ClassName#)))
  EndIf
  ;Flush ObjectName  ; <- Pity PB doesn't allow to flush a previously created variable :-|
EndMacro
;_____________________________

;====================================
;    Begin of Class Definition
;====================================
Structure cPaddle
  VTable.l
  x.l
  y.l
EndStructure
Interface iPaddle
  MoveTo(x,y) 
  GetX() 
  GetY() 
EndInterface 
Procedure.l NewObject_Paddle()
  Protected *newobject.cPaddle
  *newobject = AllocateMemory(SizeOf(cPaddle))
  *newobject\VTable = ?cPaddle_VT
  ProcedureReturn *newobject
EndProcedure
Procedure MoveTo(*Self.cPaddle, x, y)
  *Self\x = x
  *Self\y = y
EndProcedure
Procedure GetX(*Self.cPaddle)
  ProcedureReturn *Self\x
EndProcedure
Procedure GetY(*Self.cPaddle)
  ProcedureReturn *Self\y
EndProcedure
DataSection
  cPaddle_VT:
  Data.l @MoveTo(), @GetX(), @GetY()
EndDataSection
EnableClass(Paddle) ; <- Create and define Paddle Class (set ready a class to add objects of it).
;====================================
;    End of Class Definition
;====================================

; simple test program to demonstrate using the Paddle class:

New_Obj(Paddle1,Paddle)
New_Obj(Paddle2,Paddle)
New_Obj(test3,Paddle)
New_Obj(test4,Paddle)
New_Obj(test5,Paddle)

Paddle1\MoveTo(5,6)
Paddle2\MoveTo(7,8)

; Display object properties using Get methods

Debug Paddle1\GetX()
Debug Paddle1\GetY()
Debug Paddle2\GetX()
Debug Paddle2\GetY()

http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
mskuma
Enthusiast
Enthusiast
Posts: 573
Joined: Sat Dec 03, 2005 1:31 am
Location: Australia

Post by mskuma »

netmaestro wrote:This is accomplished in PureBasic using interfaces. Here's a tiny demo to show the approach using your example
Thanks a million, netmaestro - this is a great demo (and it's simple & effective). It helps me solve a problem.
Post Reply