Jump to page: 1 2
Thread overview
How to use base class & child class as parameter in one function ?
May 22

Hi all,
I have a windows gui setup like this;

class EventArgs {} \\ Base class for all messages
class MouseEventArgs : EventArgs {	// child class for handling mouse messages
    ...
    int x;
    int y;
    this(WPARAM wpm, LPARAM lpm){
	this.x = xFromLparam(lpm);
	this.y = yFromLparam(lpm);
    }
}

alias EvtFuncPtr = void function(EventArgs); // function pointer

struct MsgHandler {
    uint message ;
    HWND handle ;
    bool isActive ;
    EvtFuncPtr fnPtr;
}
// Then in my window class...
void addHandler(uint we, EvtFuncPtr fnp){ // This is error point.
	auto mh = MsgHandler();
	mh.handle = this.mHandle;
	mh.message = we;
	mh.fnPtr = fnp;
	mh.isActive = true;
	this.msgHandlerList ~= mh;  // This is a list<MsgHandler> in window class.	
}

// And in the WndProc...
auto thisWin = findWindowClass(hWnd);  // get the window class with hWnd.
auto mh = thisWin.findHandler(hWnd, message);    // get the event handler for this message & hWnd
if(mh.isActive) { // if there is an event handler fixed,
	switch (message){
	   case 512 : .. case 526 :  // if it's a Mouse messages
		auto ea = new MouseEventArgs(wParam, lParam);
		mh.fnPtr(ea);   // execute that event handler function
		break;
	   default : break;
	}
}

// And this is the window creation site...
auto app = new Application() ;
auto frm = new Window(app) ;
frm.createWindow() ;

frm.addHandler(frm.load, &onLoad);
frm.addHandler(frm.Click, &onClick);

void onLoad(EventArgs e){
	log("form is loaded...");
}
void onClick(MouseEventArgs e){	 // Compiler wants to change the MouseEventArgs with EventArgs.
	log("form clicked on x = ", e.x, ", and y = ", e.y);
}

I wrote  EventArgs as the parameter type in function pointer but i want to use it's child classes also. But i can't.

May 23
if (Child child = cast(Child)parent) {
	assert(child !is null);
}
May 22
On Friday, 22 May 2020 at 12:21:25 UTC, rikki cattermole wrote:
> if (Child child = cast(Child)parent) {
> 	assert(child !is null);
> }

Actually, problem occurs in addHandler function. It expects an argument of type "EventArgs", not MouseEventArgs.
May 22
On 5/22/20 9:10 AM, Vinod K Chandran wrote:
> On Friday, 22 May 2020 at 12:21:25 UTC, rikki cattermole wrote:
>> if (Child child = cast(Child)parent) {
>>     assert(child !is null);
>> }
> 
> Actually, problem occurs in addHandler function. It expects an argument of type "EventArgs", not MouseEventArgs.

Yes, because what if you did this with your function:

fnp(new EventArgs(...));

It would be called with the type being implicitly cast to the child type without that being true.

What Rikki was recommending is that you write your handler like this:

void onClick(EventArgs e){
    if(auto me = cast(MouseEventArgs)e) {
    log("form clicked on x = ", me.x, ", and y = ", me.y);
    }
}

Actually, if you are certain it's a programming error for onClick to be called with a different type of event args, I'd do:

void onClick(EventArgs e){
    auto me = cast(MouseEventArgs)e;
    assert(me !is null, "Error, onClick called with invalid event type");
    log("form clicked on x = ", me.x, ", and y = ", me.y);
}
May 22
On Friday, 22 May 2020 at 16:12:12 UTC, Steven Schveighoffer wrote:
> On 5/22/20 9:10 AM, Vinod K Chandran wrote:
>> On Friday, 22 May 2020 at 12:21:25 UTC, rikki cattermole wrote:
>>> if (Child child = cast(Child)parent) {
>>>     assert(child !is null);
>>> }
>> 
>> Actually, problem occurs in addHandler function. It expects an argument of type "EventArgs", not MouseEventArgs.
>
> Yes, because what if you did this with your function:
>
> fnp(new EventArgs(...));
>
> It would be called with the type being implicitly cast to the child type without that being true.
>
> What Rikki was recommending is that you write your handler like this:
>
> void onClick(EventArgs e){
>     if(auto me = cast(MouseEventArgs)e) {
>     log("form clicked on x = ", me.x, ", and y = ", me.y);
>     }
> }
>
> Actually, if you are certain it's a programming error for onClick to be called with a different type of event args, I'd do:
>
> void onClick(EventArgs e){
>     auto me = cast(MouseEventArgs)e;
>     assert(me !is null, "Error, onClick called with invalid event type");
>     log("form clicked on x = ", me.x, ", and y = ", me.y);
> }

Thanks for the answer. I understand that, in D, derived class and base class are not the same as in vb.net or any other language. (Please correct me if i am wrong).
In vb.net, assume that i have a class setup like this--
Public Class Base
    Public Property SampleInt As Integer
End Class

Public Class Child : Inherits Base
    Public Property SampleDouble As Double
End Class
//Assume that i have a list of Base class like this--
Dim sampleList As New List(Of Base)
// Now, i can use this list like this--
sampleList.Add(New Child(10.5)) Is this possible in D without casting ?

May 22
On Friday, 22 May 2020 at 20:04:24 UTC, Vinod K Chandran wrote:
> sampleList.Add(New Child(10.5)) Is this possible in D without casting ?

Direct translation of this code works just fine in D.
May 22
On 5/22/20 4:04 PM, Vinod K Chandran wrote:
> On Friday, 22 May 2020 at 16:12:12 UTC, Steven Schveighoffer wrote:
>> On 5/22/20 9:10 AM, Vinod K Chandran wrote:
>>> On Friday, 22 May 2020 at 12:21:25 UTC, rikki cattermole wrote:
>>>> if (Child child = cast(Child)parent) {
>>>>     assert(child !is null);
>>>> }
>>>
>>> Actually, problem occurs in addHandler function. It expects an argument of type "EventArgs", not MouseEventArgs.
>>
>> Yes, because what if you did this with your function:
>>
>> fnp(new EventArgs(...));
>>
>> It would be called with the type being implicitly cast to the child type without that being true.
>>
>> What Rikki was recommending is that you write your handler like this:
>>
>> void onClick(EventArgs e){
>>     if(auto me = cast(MouseEventArgs)e) {
>>     log("form clicked on x = ", me.x, ", and y = ", me.y);
>>     }
>> }
>>
>> Actually, if you are certain it's a programming error for onClick to be called with a different type of event args, I'd do:
>>
>> void onClick(EventArgs e){
>>     auto me = cast(MouseEventArgs)e;
>>     assert(me !is null, "Error, onClick called with invalid event type");
>>     log("form clicked on x = ", me.x, ", and y = ", me.y);
>> }
> 
> Thanks for the answer. I understand that, in D, derived class and base class are not the same as in vb.net or any other language. (Please correct me if i am wrong).
> In vb.net, assume that i have a class setup like this--
> Public Class Base
>      Public Property SampleInt As Integer
> End Class
> 
> Public Class Child : Inherits Base
>      Public Property SampleDouble As Double
> End Class
> //Assume that i have a list of Base class like this--
> Dim sampleList As New List(Of Base)
> // Now, i can use this list like this--
> sampleList.Add(New Child(10.5)) Is this possible in D without casting ?
> 

Yes. What you cannot do is this (which I hope doesn't compile in VB.net, but I wouldn't be surprised):

Dim sampleList As New List(Of Child)
sampleList.Add(New Base(10))

Which is the equivalent of what you were requesting.

-Steve
May 22
On Friday, 22 May 2020 at 20:06:20 UTC, Adam D. Ruppe wrote:
> On Friday, 22 May 2020 at 20:04:24 UTC, Vinod K Chandran wrote:
>> sampleList.Add(New Child(10.5)) Is this possible in D without casting ?
>
> Direct translation of this code works just fine in D.

Yeah, my bad. I just checked in D. But think inherited type difference is a problem in function pointer's parameters only.
alias EvtFuncPtr = void function(EventArgs);
Now, this EvtFuncPtr won't allow any derived classes of EventArgs as parameter. That's the problem i am facing. What about a template ?

alias EvtFuncPtr = void function(T)(T = EventArgs);
This is not compiled.
May 22
On Fri, May 22, 2020 at 08:55:45PM +0000, Vinod K Chandran via Digitalmars-d-learn wrote:
> On Friday, 22 May 2020 at 20:06:20 UTC, Adam D. Ruppe wrote:
> > On Friday, 22 May 2020 at 20:04:24 UTC, Vinod K Chandran wrote:
> > > sampleList.Add(New Child(10.5)) Is this possible in D without
> > > casting ?
> > 
> > Direct translation of this code works just fine in D.
> 
> Yeah, my bad. I just checked in D. But think inherited type difference
> is a problem in function pointer's parameters only.
> alias EvtFuncPtr = void function(EventArgs);
> Now, this EvtFuncPtr won't allow any derived classes of EventArgs as
> parameter. That's the problem i am facing.
[...]

So you're basically saying:

	void function(DerivedClass)

cannot implicitly convert to:

	void function(BaseClass)

right?

This is as it should be:

	class Base { ... }
	class Derived : Base { ... }
	class Another : Base { ... }

	void baseFunc(Base) { ... }
	void derivedFunc(Derived) { ... }

	void function(Base) funcPtr;
	funcPtr = baseFunc;	// OK
	funcPtr = derivedFunc;	// Not allowed

Why is it bad to assign derivedFunc to funcPtr?  Consider this:

	Base obj = new Another;
	funcPtr = baseFunc;
	funcPtr(obj);	// OK, because Another is a subtype of Base

	funcPtr = derivedFunc; // suppose this was allowed
	funcPtr(obj);	// Uh oh, derivedFunc receives an argument of
			// type Another which is not a subtype of
			// Derived

So, it's not permissible to allow assigning derivedFunc to funcPtr without a cast.


T

-- 
Indifference will certainly be the downfall of mankind, but who cares? -- Miquel van Smoorenburg
May 22
On Friday, 22 May 2020 at 20:51:20 UTC, Steven Schveighoffer wrote:
> On 5/22/20 4:04 PM, Vinod K Chandran wrote:
>> [...]
>
> Yes. What you cannot do is this (which I hope doesn't compile in VB.net, but I wouldn't be surprised):
>
> Dim sampleList As New List(Of Child)
> sampleList.Add(New Base(10))
>
> Which is the equivalent of what you were requesting.
>
> -Steve
Nope--
List(Of Base) will contain an instance of a Child.
So in the same manner, i want
void function(Base) = fnPtr wiil work with
void function(Child)

« First   ‹ Prev
1 2