Interesting polymorphic problem.

BlitzMax Forums/BlitzMax Programming/Interesting polymorphic problem.

Grey Alien(Posted 2006) [#1]
Here's the thing ...

- I have a TSprite with a Draw() method and a SpecialDraw() method.
- I extend the TSprite to TPlayer
- TPlayer also has a draw() method (overriding TSprite.draw())
- In TPlayer.Draw() I call Super.Draw() then I call Super.SpecialDraw()
- SpecialDraw() changes SetBlend to LIGHTBLEND and then draws the sprite again over the top of the original by calling Draw(). This is where the problem lies. It get's stuck in an infinite loop because when SpecialDraw() calls Draw() it doesn't called TSprite.Draw() it must be calling TPlayer.Draw() which calls SpecialDraw() again and so on.

here's some example code:

Type TSprite
   Method Draw()
   End MEthod

   MEthod SpecialDraw()
      SetBlend LIGHTBLEND
      Draw()
   End Method
End Type

Type TPlayer extends TSprite
   Method Draw() 'overridden
      Super.Draw()
      Super.DrawSpecial
   End Method
End Type


I tried changing the draw call in SpecialDraw() with a typecast:

TSprite(self).Draw()
and this has the same hang.

I tried changing typecasting Super as a TPlayer:

TPlayer(Super).Draw()
and this still hangs. Anyway this would be undersireable as it would only work for TPlayer and the whole point is I want sprites and exended sprites to be able to use SpecialDraw().

So then ... any bright ideas about how I can instruct it to call TSprite.Draw()? I know I could make TSprite.Draw() into a wrapper for another method called DoDraw() or something and then in SpecialDraw() call DoDraw() which, providing it isn't overridden in the extended type, will work (I've tested this), but that's pretty lame. There must be an easier way to do this. Ideas? Thanks in advance.


ImaginaryHuman(Posted 2006) [#2]
Did you try Self.Draw() ?

You could just duplicate the draw method and call it `LocalDraw()` or something.

But I guess you're trying to go with some kind of clever technique?


ImaginaryHuman(Posted 2006) [#3]
Or what if you do:

Local MyFunctionPtr()=Self.Draw()

MyFunctionPtr()

Does that do anything different?


taxlerendiosk(Posted 2006) [#4]
Or what if you do:

Local MyFunctionPtr()=Self.Draw()

You can't have a pointer to a method though, only functions.


AlexO(Posted 2006) [#5]
I can see why its getting stuck. But not exactly sure why you would do that. All you are changing is your blend mode and calling the same draw function, which with dynamic binding will just recursively call the closest (in this case TPlayer's) method in the heiarchy to the runtime type of that object. Hope that makes sense.

But if you're trying to alter draw SETTINGS i'd recommend abstracting it out a little more. I've used drawStates or renderstates to help with drawing special types.

so for instance

Type TSprite
   Field rState:RenderState

   Method Draw()
   End MEthod

End Type

Type TPlayer extends TSprite
   
   Method Draw() 'overridden
      Super.Draw()
      rstate.set()
      Super.Draw()

   End Method

End Type

Type RenderState
	field alpha
	field scalex
	field scaley
	field rotation
	field blend
	field r,g,b
	
	method new()
		r= 255
		g = 255
		b = 255
		alpha = 1
		rotation = 0
		scalex = 1
		scaley = 1
		blend = SOLIDBLEND
	end method

	method set()
		setcolor r,g,b
		setrotation rotation
		setalpha alpha
		setscale scalex,scaley
		setblend blend
	end method

End Type


and for player sprites you simply alter the renderState on creation and you'd be set.


Grey Alien(Posted 2006) [#6]
thanks for your help...

Did you try Self.Draw() ?
yep first thing I did.

All you are changing is your blend mode and calling the same draw function, which with dynamic binding will just recursively call the closest (in this case TPlayer's) method in the heiarchy to the runtime type of that object. Hope that makes sense.

Well it wasn't just changing the blend mode, that was an example, there's more, enough to merit a method. I get that it's calling the closest method to the runtime type, but in theory you ought to be able to call the TSprite's draw() method as well, except you can't ...

I like the renderstate idea, I was just trying to keep the draw function as simple as possible for speed, and having to check if the renderstate has changed each time is an extra bit of code I'd rather avoid ... but I may have no choice. Or I'd have to set the state before the draw, and the reset it afterwards, all in TPlayer.Draw() and I was trying to remove that many lines of code from TPlayer.Draw() and plonk them in TSprite where it can be reused. In fact what I want to call in TPlayer.Draw is this:

Super.DrawLight(DamageCounter/DamageFadeLength,1,0,0)
all on one line, thus not having to set state, draw, reset state. I know that will work, but I just want to put as much functionality in TSprite so later on I can do TAlien.Draw() and call Super.DrawLight() when it's damaged etc.


sswift(Posted 2006) [#7]
I think what Grey Alien is trying to do makes perfect sense.

The sprite type should always call it's own Draw() method when it tries to Draw() from within itself.

And the player type should call the sprite's Draw() method, unless the player type has it's own Draw() method.

It doesn't make sense for the code in the sprite type to call the player's draw method when the draw method is overridden in the player type, because then the person that wrote the sprite type cannot predict how his own functions will behave when given these overridden types.


On the other hand, if you need a player to draw in a special way, and the sprite type's update function draws all the sprites with the sprite's draw method, then in order to use that update function and have it draw the players correctly, the sprite's draw method must be overridden.


But what if the sprite's draw method counts on the fact that draw works a certain way, and it draws shadows by calling the draw mwthod after setting some blending modes? Then that shadow casting functionality will break as soon as the user who wrote the player type overrides the sprite type.

This doesn't seem like it prevents bugs to me. It seems to me that if the aim is to have objects that you don't need to consider the internals of when making new objects, that having methods that override the methods another type calls itself internally is a very bad thing.

On the other hand, being able to call sprite.update() to draw all the sprites is useful, and if you can't override the draw function your players won't be drawn correctly.

But should it be? That Sprite.Update() function is for updating sprites. And a player is not a sprite... Well, actually it is a sprite in the world of OOP. The sprite is not an object the player moves, the player is a sprite.

I think I still hate OOP.

Btw, grey, why are you making a sprite type, I thought you were using my sprite system? :-) If you've changed it, you should know it already handles drawing sprites brighter than normal and the draw function won't allow you to override the blend mode in that way. I suspect you're making your own sprite type though so that wouldn't be an issue then.


AlexO(Posted 2006) [#8]

I like the renderstate idea, I was just trying to keep the draw function as simple as possible for speed, and having to check if the renderstate has changed each time is an extra bit of code I'd rather avoid ...



This is where stacks come in handy . I refactored your original example of the types to give the same result below. Added in renderstate stacks to show you don't have to check if a renderstate has changed

example:

Type TSprite
   Field rState:RenderState

   Method Draw()
	rstate.Push()
	' draw stuff
	rstate.pop()
   End MEthod
	
	Method SpecialDraw()
		setBlend LIGHTBLEND
	end Method
End Type

Type TPlayer extends TSprite
   
 	Method Draw()
		super.draw()
		super.specialDraw()
		super.draw()
	end Method

End Type

Type RenderState
	global stack:Tlist = createList()
	field alpha
	field scalex
	field scaley
	field rotation
	field blend
	field r,g,b
	
	method new()
		r= 255
		g = 255
		b = 255
		alpha = 1
		rotation = 0
		scalex = 1
		scaley = 1
		blend = SOLIDBLEND
		
	end method

	method set()
		setcolor r,g,b
		setrotation rotation
		setalpha alpha
		setscale scalex,scaley
		setblend blend
	end method

	method push()
		stack.addLast(Self)
		set()
	end method

	method pop()
		stack.removeLast(Self)
		RenderState(stack.Last()).set()
	end method
End Type



I can't see any other way around the recursion. I imagine if you wanted specialDraw() to setup some sort of lighting algorithm you can do that in specialDraw(), but do not call Draw() in the same function. In Player you call specialDraw() then draw(). This might sound cumbersome but look at the whole picture in the end:
- when I create a player type all I have to do is calle myPlayer.draw(). no needed extra work.


AlexO(Posted 2006) [#9]

But should it be? That Sprite.Update() function is for updating sprites. And a player is not a sprite... Well, actually it is a sprite in the world of OOP. The sprite is not an object the player moves, the player is a sprite.



This is where it seems your confused. Again, look at the heiarchy

Sprite
|
|
Player extends Sprite

This says a 'Player IS A Sprite' but a 'Sprite IS NOT a player. Look at bottom of heiarchy anything above it 'Is a' of that type. you can't 'is a' down the heiarchy. Makes perfect sense...


It doesn't make sense for the code in the sprite type to call the player's draw method when the draw method is overridden in the player type, because then the person that wrote the sprite type cannot predict how his own functions will behave when given these overridden types.



the very meaning of 'overriding' a method is to replace original functionality completely.

With that said. if you had a 3000 line function in a super type and you want to derive another type that'll just change 1 line in that huge function...you're out of luck. And usually a sign of bad implementation.


Nelvin(Posted 2006) [#10]
Working the way it does is exactly why polymorphism exists (maybe you guys having problem with that should try to find a decent tutorial about the topic) if you'd call mySprite.Draw and it wouldn't call the Draw method of the concrete object mySprite points to, it wouldn't make any sense at all. It's meant to decouple your code from knowing concrete types but work with the given interfaces of it's base class.

In that specail case the solution would be to create a system without cycling contexts.

Type Sprite
	Method Draw()
		BaseDraw()
	End Method
	
	Method BaseDraw()
		Print( "BaseDraw" )
	End Method

	Method SpecialDraw()
		Print( "SpecialDraw" )
		BaseDraw()
	End Method
End Type


Type Player Extends Sprite
	Method Draw()
		Print( "PlayerDraw" )
		SpecialDraw()
	End Method
End Type	


Type SuperPlayer Extends Player
	Method SpecialDraw()
		Print( "SuperPlayerSpecialDraw" )
		Super.SpecialDraw()
	End Method
End Type


Local spr:Sprite = New SuperPlayer
spr.Draw()

now our spr is only of the base type Sprite but it calls Player.Draw() which calls SuperPlayer.SpecialDraw() doing something specialspecial, Then calls Sprite.SpecialDraw doing the standardspecial and then calls Sprite.BasicDraw
Note that you can in addition customize the BaseDraw for derived types, but you first have to get what in that sample happens and *why*, then you shouldn't have problems with this in the future.


sswift(Posted 2006) [#11]

This is where it seems your confused. Again, look at the heiarchy

Sprite
|
|
Player extends Sprite

This says a 'Player IS A Sprite' but a 'Sprite IS NOT a player. Look at bottom of heiarchy anything above it 'Is a' of that type. you can't 'is a' down the heiarchy. Makes perfect sense...




I'm not confused at all, because I said that that is how it is right after I said it was another way. I said it was the other way first to point out how confusing and backwards OOP can be. It may make sense from an OOP standpoint that a player is a sprite, but as far as I'll always be concerned, a sprite is a polygon on the video card, and the player is moving it. The player is not a sprite, it controls a sprite.


now our spr is only of the base type Sprite but it calls Player.Draw() which calls SuperPlayer.SpecialDraw() doing something specialspecial, Then calls Sprite.SpecialDraw doing the standardspecial and then calls Sprite.BasicDraw



I can now see how OOP is not confusing at all!
/sarcasm


Azathoth(Posted 2006) [#12]
It doesn't make sense for the code in the sprite type to call the player's draw method when the draw method is overridden in the player type, because then the person that wrote the sprite type cannot predict how his own functions will behave when given these overridden types.

This is how virtual methods work, it makes perfect sense.


Grey Alien(Posted 2006) [#13]
wow the debate rages on.

Sswift: I've had a TSprite for ages in the framework. I was just adding some extra functionality today for when the player/alien gets hit, so they can flash brighter. Glad you can see my point. The rest of the OOP is fine, but there ought to be a way to call the base type Draw() in fact that's what I'm expecting it to do in this case, but it doesn't... Actually there are cases where you *wouldn't* want it to call the base type Draw() as well when in TSprite so I guess it's swings and roundabouts.

Alex.O: nice bit of code thanks.

Nelvin: Don't worry I understand OOP and Polymorphism fine. I already thought of making a wrapper for Draw() as per my first post where I mentioned DoDraw(). But I decided this was less desirable if there was a quick and easy way to be able to call the basetype's draw() from within itself, rather than it calling the exended type's overridden draw().

If you are able to call super.draw() from within TPlayer, why can't you can't draw() in some special way within TSprite and have it call TSprite's draw()? I can see why "self" fails, because self is still a TPlayer. So I typecasted self as TSprite but that still didn't work because polymorphism is still working of course. So it sounds like basically there is no way to do this without making a wrapper function to avoid "cycling contexts", or using renderstates ... sigh. The code is working fine right now using a wrapper function, I just found that a bid sad :-(


dmaz(Posted 2006) [#14]
It doesn't make sense for the code in the sprite type to call the player's draw method when the draw method is overridden in the player type, because then the person that wrote the sprite type cannot predict how his own functions will behave when given these overridden types.

yes it does make perfect sense. if the extended type overrides the base draw that means the extended type (TPlayer) must be doing something that the base draw can’t. which means that the base now has NO IDEA how to draw TPlayer correctly. It must use TPlayer’s draw! The base class assumes that TPlayer will use the base draw when appropriate, which is up to the programmer.

If the programmer of TSprite didn’t want draw overridden he should finalize the method.


dmaz(Posted 2006) [#15]
If you are able to call super.draw() from within TPlayer, why can't you can't draw() in some special way within TSprite and have it call TSprite's draw()? I can see why "self" fails, because self is still a TPlayer. So I typecasted self as TSprite but that still didn't work because polymorphism is still working of course. So it sounds like basically there is no way to do this without making a wrapper function to avoid "cycling contexts", or using renderstates ... sigh. The code is working fine right now using a wrapper function, I just found that a bid sad :-(


TPlayer needs to decide which draw to use... NOT the base because the base doen't have all the information


dmaz(Posted 2006) [#16]
here's the thing Grey. what you want to do is not logical. your base is fine and makes perfect sense but your TPlayer is not right because your're calling specialdraw from draw... when specialdraw already calls draw. doesn't make sense.

what you should be doing is overriding specialdraw.... because it is a specialdraw by the fact that you are calling the base specialdraw.
Type TSprite
   Method Draw() Final
      Print "base draw"
   End Method

   Method SpecialDraw()
      Print "base superdraw"
      Draw()
   End Method
End Type

Type TPlayer Extends TSprite
   Method SpecialDraw() 'overridden
      Print "player - start sdraw"
      Super.Draw()
      Super.SpecialDraw()
      Print "player - end sdraw"
   End Method
End Type

Local t:TPlayer = New TPlayer
t.SpecialDraw()


[edit] actually, looking at it again... I would probably do what Nelvin suggested with draw, basedraw and specialdraw but I would make basedraw final


sswift(Posted 2006) [#17]
Well I understand what you're saying but it still seems backwards to me.

I look at it like this. Each class I create should be like a library.

I can see the interface to library. I can access the functions and fields it provides to me. But what goes on inside it is a mystery, and I have no access to it.

Is not the idea of OOP that objects are encapsulated, and only those parts that you want accesses you make acessable, and the other fields you make private?

If we go back to the physics library example now, if you imagine there is a function for calculating distance, I could "override" that function in my code. I could make my OWN distance function with the same name. In doing so, my own code would access that distance function instead of the one in the physics lib. But the physics lib itself would remain unaffected. It would continue to use it's own distance function. And that's good, because I'm not supposed to look at it's internals! Everything I need to access it is supposed to be available from it's interface.

But what you're suggesting... Overriding the draw function of the sprite class, in such a way that the sprite class now calls that draw function instead... That's like hacking into the class to change it's behavior. It seems to me that that goes against the OOP philosophy.

If I use a calculator as an example...

The caclulator has a display. Tat display is physically capable of drawing the numbers 0 thru 9.

The calculator has a CPU. The CPU knows how to take input, and tell the display what numbers to display, but it cannot alter the display to be capalbe of showing letters.

The buttons know how to take input from the user and provide that input to the CPU. But the buttons can't change how the CPU's SINE function works. If the CPU's SINE function takes radians normally, and you need it to take degrees, you don't tell the buttons to alter the CPU's sine function, you directly alter the CPU itself.

Is this not the concept behind OOP? Each object is self contained, and a model of the real world? What you suggest, having an object change the sprite's draw function is like having the buttons tell the calculator's CPU that it should take degrees inatead os radians in it's sine function. And that is obviously silly.

So if your sprite type doesn't know how to draw fruit, then it needs to be updated to draw fruit. But you don't have the fruit type make that change, you go into the sprite type and make the change.

If OOP deisign says to do otherwise, then OOP isn't OOP at all, if OOP is supposed to be based on objects in the real world!


dmaz(Posted 2006) [#18]
If we go back to the physics library example now, if you imagine there is a function for calculating distance, I could "override" that function in my code. I could make my OWN distance function with the same name. In doing so, my own code would access that distance function instead of the one in the physics lib. But the physics lib itself would remain unaffected. It would continue to use it's own distance function. And that's good, because I'm not supposed to look at it's internals! Everything I need to access it is supposed to be available from it's interface.

Same here! The base physics “type” WILL (as with the lib) continue to use it’s own distance function and remains unaffected just like the lib you describe above. It will do this even if it’s been extended but only for it’s own objects. tplayer’s objects are tplayer’s objects, as such it needs to manage them.

But what you're suggesting... Overriding the draw function of the sprite class, in such a way that the sprite class now calls that draw function instead... That's like hacking into the class to change it's behavior. It seems to me that that goes against the OOP philosophy.

but that’s exactly what you are doing… changing it’s behavior. As a developer you need take this into account. That’s what word like “final” and “abstract” are for. Also I would like to point out the VERY important fact that the sprite clase ONLY calls the player draw when the object is a player….. in other words, when the developer of the player type wants it to.

Tell me, how can the developer of the sprite class know when to call and when not to call something he’s never seen (if the authors are different)?

Tsprite is NOT tplayer… tplayer is like a whole new lib built using the foundation of tsprite.


dmaz(Posted 2006) [#19]
First your calculator example is poor because those are all separate objects that work together. they are not objects built on one another.... they are not OOP

Is this not the concept behind OOP? Each object is self contained, and a model of the real world?

yes, each type is as self contained as the developer needs or wants it be. Tell me, how is TSprite not self contained?

What you suggest, having an object change the sprite's draw function is like having the buttons tell the calculator's CPU that it should take degrees inatead os radians in it's sine function. And that is obviously silly.
the object ISN'T changing the sprite's draw function! it's OVERRIDING it... which mean exactly what that says.... since it overridden you can't use it (unless tplayer directly calls it)

it's kinda bothering me why you're not following this... what you're saying seems so illogical to me.... but I remember going through this myself.


Nelvin(Posted 2006) [#20]

If I use a calculator as an example...

The caclulator has a display. Tat display is physically capable of drawing the numbers 0 thru 9.

The calculator has a CPU. The CPU knows how to take input, and tell the display what numbers to display, but it cannot alter the display to be capalbe of showing letters.

The buttons know how to take input from the user and provide that input to the CPU. But the buttons can't change how the CPU's SINE function works. If the CPU's SINE function takes radians normally, and you need it to take degrees, you don't tell the buttons to alter the CPU's sine function, you directly alter the CPU itself.



Now take your example and think of about displaying the numbers using an LCD and alternatively LEDs (not in terms of using different bitmaps, but real different ways of displaying them, be it hardware or f.i. using bitmaps for LCDs and vector shapes for LEDs).

If you give the CPU an LCDDisplay type and use that, you cannot change the behaviour without altering the CPU code - if you use an abstract CalcDisplay just defining the interface and implement derived types LCDDisplay and LEDDisplay you can use instances of both and just hand them to the CPU as a CalcDisplay because the CPU really isn't interested in the concrete type of display.


sswift(Posted 2006) [#21]
"First your calculator example is poor because those are all separate objects that work together. they are not objects built on one another.... they are not OOP"


Okay, then let's use an example that works with OOP as you see it.


I have a car. The car has a generic engine, tires, and chassis. Those aren't objects however, those are the car's methods.

If I want I can make the car into a volvo. To do that though, I need to replace the engine, tires and chassis. The car still knows how to use these things, but they're different on the volvo and the generic car.

I can go one step further, and upgrade to a Volvo SE. That comes with additional features like heated seats and power windows that the car doesn't know how to use or need to know how to use. But I can access them if I have the Volvo SE.


So now let's go back to the sprite system. Let's say my sprite is a junker. It has bald tires, and shimmies at 30mph. I want to replace it's draw "engine" to make it go fast.

Would you say it would be wise for me to just strap a jet engine on the back of that puppy to take over for the failing engine? Probably not. For one, those tires are bald. And for another, I don't know if the car's body would take the stress. It might just tear itself apart. Also, the weight of the car, and how it behaves at high speed are important to know or I could just flip over, or be unable to steer.

Once you start overriding methods in a class, you need to know how that class, and all the classes that it is desired from, work, in great detail, or you're just asking for a darwin award.

And that just doesn't seem like a safe and reliable way to program to me.


AlexO(Posted 2006) [#22]

Once you start overriding methods in a class, you need to know how that class, and all the classes that it is desired from, work, in great detail, or you're just asking for a darwin award.



using your car example... if I wanted to make my car go faster I would imagine I would have to know in relative 'great detail' how engines work to even consider altering/overriding some of its functionality or I'll end up with an even bigger pile of junk :D. Same I would think applies to overridding methods in Bmax.


Grey Alien(Posted 2006) [#23]
Well like I said, I already had code in place like Nelvin's and I'm sticking with that for now. But like swift said, if this was function-based programming I *would* be able to call SpriteDraw() and it would work fine.


IPete2(Posted 2006) [#24]
Grey,

Why not simply set a flag and have only one draw routine. Send everything to the same routine and divert to additional blend features (Special Draw method) with the flag?

IPete2.


Grey Alien(Posted 2006) [#25]
IPete2: yes I could do that. In fact as soon as it didn't work I thought of several methods. My point was really why can't I call TSprite.Draw() when the object is a TPlayer. I know *why* it calls TPlayer.Draw() instead but I just wondered if there was a way to do what I wanted in that way, just for interest really.


Nelvin(Posted 2006) [#26]
Ok guy's either you don't get the benefits of polymorphic programming (it's designed to solve the problems of setting a flag for special handling because that's pretty bad if you have to maintain your code for a long time) or you just have that small projects that it really doesn't matter - then why bother, just skip the stuff and code however it's best suited for you. That's not a bad decision at all - in the end what really counts are the results.

An engine is not a method - the difference between a method and an object is it's state. An engine holds lots of states like age, number of runs, current speed, power etc..
Another example - powersuply in your house - you think your sockets should have "methods" for a TV, for a toaster, for a pc? Or isn't it better (well there's no chance one can question that) to have an abstract interface just for supplying energy to whatever "user" usese that common interface. Note the slight difference, the way you think about programming at the moment would be that your socket has methods like PowerToaster(), PowerTV() moving the usage decision to the wrong side of the fence.


skidracer(Posted 2006) [#27]
That is interesting. Casting to the base class does work in C++ and I don't quite see why Max behaves differently although Max doesn't have multiple inheritance so maybe doesn't fit with the optimal design:

test.bmx prints "b+"
Type a
	Method b()
		Print "b"
	End Method
End Type

Type aa Extends a
	Method b()
		Print "b+"
	End Method
End Type

Local a1:aa=New aa
a(a1).b


test.cpp prints "b"
#include <stdio.h>

struct a{
virtual void b(){printf("b\n");}
};

struct aa:a{
virtual void b(){printf("b+\n");}
};

main(){
	aa a1;
	a(a1).b();
}



Grey Alien(Posted 2006) [#28]
There we go, I knew it was possible, just not in Max.

What happens in C++ if you create a variable of type a called x and typecast aa to it (x=a(a1)), and then call a.b(). Surely then it will print "b+" because it's using polymorphism. This is actually an inconsistency really isn't it? They should both do the same thing. However, it should also be possible to call the baseclass method too, so that developers can have the best of both worlds.

Nelvin: I get it. I don't have any flags. My polymorphic code works fine, I just wondered if this extra little option of calling a base class method within the base class was possible that's all.


Nelvin(Posted 2006) [#29]
Your C++ sample is wrong.
Polymorphism is only a topic on pointer/references.
What your sample does, is creating a concrete, known instance of the derived type.

And then you use that to create a concrete instance of the base type (a temporary but still an object, this has nothing to do with casting pointer/reference types) which the compilier initializes using a default copy constructor created automatically (because you didn't implement one).

Seems like you'd be surprised that the results would be different by changing the code to:
main(){
aa* a1 = new a();
a* a2 = a1;
a2->b();
}


which is the way max works and how it generally is suppost to work using virtual/abstract methods.

@Grey - it wasn't aimed at you, more to the generality having problems with the topic - I should probably use more quotes :-)


skidracer(Posted 2006) [#30]
Ooops. :)


Grey Alien(Posted 2006) [#31]
hah, I've been trying to test this but my Visual Studio Beta has expired. So I tried Borland C which I had on my drive, but turns out that was from before my current install of XP (infact it's probably from a win98 install ages ago) thus woudn't run. So I dropped back to the DJGPP compiler with RHIDE but that crash out a lot in XP, so I ran it in DOSBOX, but it still generated in errors. So out of compilers, I've decided to update my MS stuff to the latest free visual studio express. However I uninstalled the old stuff in the wrong order; did .net framework 2 first then SQL server wouldn't uninstall without it, how naff is that. So I had to download and reinstall it just to uninstall SQL server gah! Anyway, now I need a reboot (hope that doesn't fail, if you don't see any posts of mine for a few days, you now XP has gone *bad*) then I can finally download and install the new stuff so I'm back with the modern world in terms of C++ and C# compilers!

Hey Blitz Max compile c++? I can can't it? How do I do that...?


skidracer(Posted 2006) [#32]
You name the file blah.cpp and press f5...


Grey Alien(Posted 2006) [#33]
cool thanks haha, that easy heh. Well sod the MS pap. Hey I could get my old Allegro stuff working again!


Grey Alien(Posted 2006) [#34]
@Nelvin: This doesn't compile it says "invalid conversion from `a*' to `aa*'"
main(){
aa* a1 = new a();
a* a2 = a1;
a2->b();
}


did you mean to put aa* a1 = new aa() ? This fixes the problem and demonstrates your point.

btw...
There we go, I knew it was possible, just not in Max.
I take it back :-(