Hi, I've been away from PowerBasic for a while but being interested in OO programming decided to examine how this is implemented in PB10. On first glance it looks very good and certainly fills many boxes. I'm not currently implementing any COM based software, but pleased that the developers included the ability to create non COM based classes along with class inheritance.
To try out PB's capabilities I knocked up a 3D Vector class (See below) to see how it compares to the likes of C++ and C#. Despite the slight syntactical differences all went fairly smoothly. I have noticed a few things which would be nice if added, and also something which at first thought was missing but I seem to have found a way around. To explain I have included a smaller program below which defines a base class along with a derived class. In this example I wanted to see if I could create C++’s equivalents of private and protected field members. Perhaps I have missed this in the documentation or it’s mentioned elsewhere on the forum, but anyway as I now understand it, instance variables are equivalent to C++’s private fields. This means that external code including derived classes do not have access to these instance variables. But, how about protected fields, are these possible in PB10? Protected fields are very good when using inheritance because any classes derived from a base class with protected fields then have their own set of these protected fields. Without this you would have to define the same fields again in each derived class.
I have discovered that Global fields defined before the interface section within a class do appear to act as per protected fields! Here is the example:
In the above code I have commented out the lines that wont compile. It can be seen that if trying to access the InstanceVal instance variable from within the Derived class this is a no go, which confirms that it is indeed private. On the other hand, the GlobalVal variable is accessible from within the derived class. In fact, the derived class gets it’s own version which by default is set to 0. In the example I have assigned it a value of 20 within the derived class’s constructor. However, both of these field values are invisible to the object users as can be seen with the commented out code in Function PBMain. This confirms to me that we do have private and protected capability.
Now for my 3D Vector class example. This showed me how to construct a PB10 class with properties, using a constructor, along with public and private methods. The class provides the usual methods associated with 3D vectors and highlights how it would be nice if we could overload the operators such as +, -, * etc. Additionally, overloaded constructors and methods would be nice!
Here is the code which I hope some may find useful:
Thanks for reading!
To try out PB's capabilities I knocked up a 3D Vector class (See below) to see how it compares to the likes of C++ and C#. Despite the slight syntactical differences all went fairly smoothly. I have noticed a few things which would be nice if added, and also something which at first thought was missing but I seem to have found a way around. To explain I have included a smaller program below which defines a base class along with a derived class. In this example I wanted to see if I could create C++’s equivalents of private and protected field members. Perhaps I have missed this in the documentation or it’s mentioned elsewhere on the forum, but anyway as I now understand it, instance variables are equivalent to C++’s private fields. This means that external code including derived classes do not have access to these instance variables. But, how about protected fields, are these possible in PB10? Protected fields are very good when using inheritance because any classes derived from a base class with protected fields then have their own set of these protected fields. Without this you would have to define the same fields again in each derived class.
I have discovered that Global fields defined before the interface section within a class do appear to act as per protected fields! Here is the example:
HTML Code:
#Compile Exe #Dim All Class BaseClass ' Private: Instance InstanceVal As Long ' Protected: Global GlobalVal As Long ' Public Constructor. Class Method Create() InstanceVal = 12 GlobalVal = 10 End Method ' Public Destructor. Class Method Destroy() End Method 'Public: Methods and properties only Interface BaseInterface Inherit IUnknown Method GetInstanceVal() As Long Method = InstanceVal End Method Method GetGlobalVal() As Long Method = GlobalVal End Method End Interface End Class Class DerivedClass Class Method Create() 'Not visible in derived class, therefore private! 'InstanceVal = 13 'Only visible from base class and derived classes, therefore protected! GlobalVal = 20 End Method Class Method Destroy() End Method Interface DerivedInterface Inherit BaseClass, BaseInterface End Interface End Class Function PBMain () As Long Local hWin As Long Txt.Window("Text Window - Private Fields", 200, 200, 15, 80) To hWin Local d As DerivedInterface d = Class "DerivedClass" Txt.Print "d.GetInstanceVal() = " + Str$(d.GetInstanceVal()) Txt.Print "d.GetGlobalVal() = " + Str$(d.GetGlobalVal()) 'd.InstanceVal not visible 'txt.print "d.InstanceVal = " + str$(d.InstanceVal) 'd.GlobalVal not visible 'txt.print "d.GlobalVal = " + str$(d.GlobalVal) Txt.WaitKey$ End Function
Now for my 3D Vector class example. This showed me how to construct a PB10 class with properties, using a constructor, along with public and private methods. The class provides the usual methods associated with 3D vectors and highlights how it would be nice if we could overload the operators such as +, -, * etc. Additionally, overloaded constructors and methods would be nice!
Here is the code which I hope some may find useful:
Code:
#Compile Exe #Dim All Class Vector3Class ' Private. Instance variables are contiguous in memory! Instance X, Y, Z As Single ' Public - Constructor. Class Method Create() X = 0.0 : Y = 0.0 : Z = 0.0 End Method ' Can't have overloaded constructors! 'Class Method Create() ' X = 1.1 : Y = 1.1 : Z = 1.1 'End Method ' Public - Destructor. Class Method Destroy() ' Nothing to do End Method ' Private. Class Method getLength() As Single Method = Sqr(X*X + Y*Y + Z*Z) End Method ' Public: Methods and properties only. Interface Vector3 Inherit IUnknown Property Get X As Single Property = X End Property Property Set X (ByVal xval As Single) X = xval End Property Property Get Y As Single Property = Y End Property Property Set Y (ByVal yval As Single) Y = yval End Property Property Get Z As Single Property = Z End Property Property Set Z (ByVal zval As Single) Z = zval End Property Property Get Length As Single Property = me.getLength() End Property Property Get Magnitude As Single Property = me.getLength() End Property Method Normalise() Local vLen As Single vLen = me.length() ' Divide each component by the length. X = X / vLen : Y = Y / vLen : Z = Z / vLen End Method ' Ideally PB would have overloaded operators. ' To check for equality we want to write if Vector1 = Vector2 then... ' not if Vector1.Equals(Vector2) then... Method Equals(vector As Vector3) As Byte If( me.X = vector.X And me.Y = vector.Y And me.Z = vector.Z ) Then Method = 1 Else Method = 0 End If End Method ' Ideally PB would have overloaded operators. ' We want to be able to write NewVector = Vector1 + Vector2 ' instead of NewVector = vector1.Plus(vector2) Method Plus(vector As Vector3) As Vector3 Local sum As Vector3 sum = Class "Vector3Class" sum.X = X + vector.X sum.Y = Y + vector.Y sum.Z = Z + vector.Z Method = sum End Method ' Ideally PB would have overloaded operators. Method Minus(vector As Vector3) As Vector3 Local subtract As Vector3 subtract = Class "Vector3Class" subtract.X = X - vector.X subtract.Y = Y - vector.Y subtract.Z = Z - vector.Z Method = subtract End Method ' Ideally PB would have overloaded operators. ' We want to be able to write NewVector = Vector1 * scalar ' not NewVector = Vector1.Times(scalar) Method Times(scalar As Single) As Vector3 Local p As Vector3 p = Class "Vector3Class" p.X = X * scalar p.Y = Y * scalar p.Z = Z * scalar Method = p End Method ' Ideally PB would have overloaded operators. ' We want to be able to write Value = Vector1 * Vector2 ' not Value = Vector1.dot(Vector2) Method dot(vector As Vector3) As Single Method = X * vector.X + Y * vector.Y + Z * vector.Z End Method ' Ideally this would be an overloaded constructor. ' That way we could set the vector values on creation, making it more efficient. Method Vector3(ByVal xval As Single, ByVal yval As Single, ByVal zval As Single) X = xval : Y = yval : Z = zval End Method ' Ideally this would be an overloaded constructor. ' Same comment as above. In this case we are setting the Vector fields from an array. Method VectorArray(ByVal pCoords As Single Ptr) X = @pCoords[0] : Y = @pCoords[1] : Z = @pCoords[2] End Method ' Returns vector as a pointer to an array. ' In C++ we could override the float cast operator ' to return the address of the array. But I think ' the overloaded operators above would be the most wanted. Method toSingleArray() As Single Method = VarPtr(X) End Method End Interface End Class Function PBMain () As Long Local hWin As Long Dim coords(0 To 2) As Single Txt.Window("Text Window - Vector3", 200, 200, 20, 80) To hWin Local u, v, w As Vector3 u = Class "Vector3Class" v = Class "Vector3Class" w = Class "Vector3Class" coords(0) = 1.0 : coords(1) = 2.0 : coords(2) = 3.0 v.VectorArray(VarPtr(coords(0))) w.Vector3(-5.0, 2.0, 0.0) ' Print the three vectors Txt.Print "Vector u: X = " + Str$(u.X) + " Y = " + Str$(u.Y) + " Z = " + Str$(u.Z) Txt.Print "Vector v: X = " + Str$(v.X) + " Y = " + Str$(v.Y) + " Z = " + Str$(v.Z) Txt.Print "Vector w: X = " + Str$(w.X) + " Y = " + Str$(w.Y) + " Z = " + Str$(w.Z) ' u = v + w u = v.Plus(w) Txt.Print "Vector u: X = " + Str$(u.X) + " Y = " + Str$(u.Y) + " Z = " + Str$(u.Z) ' Normalise v.Normalise() Txt.Print "Vector v: X = " + Str$(v.X) + " Y = " + Str$(v.Y) + " Z = " + Str$(v.Z) Txt.Print "v.length() = " + Str$(v.length()) ' dotP = u * w ' single val = u.dot(w) Local dotP As Single dotP = u.dot(w) Txt.Print "u.dot(w) = " + Str$(dotP) Local VecByScalar As Vector3 VecByScalar = Class "Vector3Class" VecByScalar.VectorArray(VarPtr(coords(0))) Txt.Print "Vector : X = " + Str$(VecByScalar.X) + " Y = " + Str$(VecByScalar.Y) + " Z = " + Str$(VecByScalar.Z) ' NewVector = Vector * scalar VecByScalar = VecByScalar.Times(10.0) Txt.Print "Vector * scalar : X = " + Str$(VecByScalar.X) + " Y = " + Str$(VecByScalar.Y) + " Z = " + Str$(VecByScalar.Z) ' Get vector as an array. Dim vecarray(0 To 2) As Single At v.toSingleArray() Txt.Print "X = " + Str$(vecarray(0)) + " Y = " + Str$(vecarray(1)) + " Z = " + Str$(vecarray(2)) v.VectorArray(VarPtr(coords(0))) Txt.Print "Vector v: X = " + Str$(v.X) + " Y = " + Str$(v.Y) + " Z = " + Str$(v.Z) w.Vector3(-2.0, -1.0, -3.0) Txt.Print "Vector w: X = " + Str$(w.X) + " Y = " + Str$(w.Y) + " Z = " + Str$(w.Z) ' u = v - w u = v.Minus(w) Txt.Print "Vector v - w: X = " + Str$(u.X) + " Y = " + Str$(u.Y) + " Z = " + Str$(u.Z) Txt.WaitKey$ End Function
Comment