Event handlers vs. base class method overrides - Page 2
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 2 FirstFirst 12
Results 16 to 22 of 22

Thread: Event handlers vs. base class method overrides

  1. #16
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,587

    Re: Event handlers vs. base class method overrides

    Quote Originally Posted by TheGreatCthulhu View Post
    And I really wanted to understand all this; so, I downloaded C++/CLI specification from here (although I suspect that I already have in some obscure folder, as it might have installed with VS).
    Wow! I had no idea there might be something like a C++/CLI standard. I always somehow presumed it was an MS homegrown thing. However, the document on that ECMA page is only about 15% the size (in bytes) of the N3126 C++0x standard draft I have here. Does it only specify the differences between standard C++ and C++/CLI?

    Which means that what you highlighted uses the pointer-to-member-function syntax. (For non-member or static function, the '&' is optional, for member functions it is required.)
    Yes after some thinking I see no other option than a pointer-to-member-function too. I remember once having read something about the C++/CLI syntax for these pointers but couldn't find it again. I'm relatively sure it uses the * to designate a pointer unlike the usual C++/CLI habits. (And I think it actually is a pointer rather than a tracking handle because member functions of course are not stored in the GC heap.) I came to the conclusion that the type signature of the parameter I highlighted some posts back must at least be something similar to void (Component::*)(Object ^, MouseEventArgs ^).

    While the use of * above looks justified, I think it is arguable when explicitly specifying dereferenciation of a tracking handle like in this snippet from a form load handler:

    Code:
      Object ^objTemp = config["windowLocation"];
      if (objTemp) {
        Point pnt = *dynamic_cast<Point ^>(objTemp);
        if (pnt != Point(-1, -1)) Location = pnt;
      }
    I probably might have been able to write that more elegant using implicit unboxing but this is from one of my real apps and one of those working things I didn't change (yet).

    The fact that the MulticastDelegate constructor to which you referred in post #11 takes an Object ^ along with a string holding the name of the method to call reminds me to the use of Type::InvokeMember() like in some sample code I wrote or a combination of Type::GetMethod() and MethodInfo::Invoke() I used in a module used in as of now two of my apps. Both ways of method invocation essentially take a pointer to the object to refer to (which may/must be nullptr if the method is either static, global or namespace-scope) and a string holding the name of the method to call. I have used both ways to call a late-bound method just once yet and can't decide which one actually is more convenient, more efficient or preferable for other reasons.

    In native C++, a regular function pointer and a pointer-to-member have different internal representation (as pointed out here) - I'm guessing that it's similar in C++/CLI, and that this internal data structure is somehow mapped to what the CLR expects.
    Your guess is probably right. As I already pointed out above, function pointers in C++/CLI probably need to be actual pointers while the this reference to the object the pointer is bound to needs to be a tracking handle. So in C++/CLI a pointer-to-member-function seems to be some kind of hybrid thing.

    BTW, this was really exciting, because while digging I've discovered something that I wasn't aware of; the thing is, native C++ pointers to member functions support polymorphism, so if the inheriting class overrides the base member, the derived implementation gets called. It made me wonder if the same goes for delegates in .NET, and my first quick tests indicate that it does! I had no idea!
    Fascinating! I always thought of a pointer-to-member-function (in native C++) as a mere bundle of a pointer to the function code and a this pointer. I didn't have an idea either that they can do such fancy things. Now that I know of it it seems just logical, though. I never had a need for that yet (and an extremely rare need for pointers-to-member-functions at all except for creation of .NET delegates) but I feel the probability is high that sometime the day will come when it's good to know that...

    [...] Anyway, I wouldn't call them "helper types", as these directly support .NET infrastructure - these are at the very core of the .NET type system.
    Ok, I must admit I terribly underrated them. They actually implement the vast majority of functionality of the typed that implicitly are derived from them and thus are of invaluable importance despite the fact that "normal" developers will never have to deal with them directly. Compiler developers, however, are likely to actually do that relatively frequently.

    I was talking both native C++ and C++/CLI, but honestly, I had native C++ in mind. Don't get me wrong: I'm not questioning C++ as a language - I'm just saying that C++ is not "hardcore" OO - as opposed to languages on the other extreme, like Smalltalk (where even classes are objects, whose class is Metaclass... o_O). [...] OOP principles are really good design principles, but as you yourself noted, practical considerations (including the current evolutionary state of software and hardware) sometimes dictate that things need to be done differently in certain aspects.
    Oh, yes, ok... I often tend to forget about that. Although I was talking about the "pure doctrine" of encapsulation (I think that was in this very thread here) I ignored the fact that C++ itself is by no means a "pure doctrine" laguage. Probably this is mostly due to the two facts that C++ was my first encounter with OO and that I do practically all my OO-related work in C++ (well, and C++/CLI in the last few months).

    I know that Smalltalk often is referred to as the flagship among the OO languages, but I think there have been some languages catching up during the last years, didn't they (whatever they are - can't think of any particular one right now)?

    If language syntax is the this interface used by developers (clients) to communicate to the compiler, then I might have some dissatisfaction with it.
    To be honest, I don't understand the sentence above. Is the word "this" in it in some way related to the this pointer (in C++) or handle (in C++/CLI)?

    For example, native C++ provides delete, and delete[] - this has probably been pain for anyone learning C++. But, really, why is such a distinction needed? From the perspective of the developer (client) - who cares?! Why not just one keyword - internally, the compiler could transform it to whatever it wants.
    Ok, now you really just made me doubting something I was accepting as a standing fact during the past years... (1) Initially I was wondering myself why there's a need for two distinct variants of delete. (2) I then sometime came to the conclusion that the need for the distinction is based on the fact that the destructor only needs to be called once for a single object and more than once for an array (for non-POD types only, of course). Can't the runtime determine whether it's an array of objects or a single object (or an array comprising just a single object) from the size of a single object and the size of the memory block to be released? But what if the underlying OS can't provide the information on the size of the memory block (for some really weird reason)? (3) - and that's what just came to my mind right now: If the OS really shouldn't be able to provide the information about the size of the memory block, then how is the runtime supposed to determine for how many array elements to call the destructor in case of a delete []?

    Then, take the function pointers and pointers to member functions. There is a difference, sure, internal representations are different, but again - why do I need to know this?
    I can't really come up with the syntax to call a member function via a pointer-to-member-function but wouldn't simplifying the calling syntax too much severely obscure the actual meaning of the statement? Yes, the pointer-to-member-function (in its simplest form) holds both the pointer to the object as well as to the function so there's no information needed besides the pointer and the parameters to pass. But applying maximum simplification would make the call via the pointer look like a direct call to a member function in the scope of the class the call is made from (hmmm, is there really no more compact term for that? ) or a global function (ignoring namespace-scope functions here that I consider to be globals anyway).

    Or take the C++ style casting operators.
    I haven't made my peace with them yet either but I think I won't condemn them before I positively know they're not justified.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  2. #17
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,587

    Re: Event handlers vs. base class method overrides

    Quote Originally Posted by TheGreatCthulhu View Post
    For example, native C++ provides delete, and delete[] - this has probably been pain for anyone learning C++. But, really, why is such a distinction needed? From the perspective of the developer (client) - who cares?! Why not just one keyword - internally, the compiler could transform it to whatever it wants.
    I just found this blog entry (including comments) that may interest you in this respect: http://blogs.msdn.com/b/oldnewthing/.../03/66660.aspx. It probably won't answer all your questions about this topic but may spark further discussion. (Of course this would then need to take place in one of the native C++ sections because array allocation in .NET is a completely different thing.)

    I found that link in a thread in the Non-VC++ section which is dedicated to just that topic but IMO not as much to the point as the blog entry, at least not yet. Maybe joining that thread for further discussion is an option. (I have been following that thread anyway since it started - just about 24 hours ago but the thread is already comprising 16 posts.)
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  3. #18
    Join Date
    Jan 2010
    Posts
    1,099

    Re: Event handlers vs. base class method overrides

    Quote Originally Posted by Eri523 View Post
    Does it only specify the differences between standard C++ and C++/CLI?
    I guess - looking at the contents, you can see it mostly focuses on .NET and C++/CLI specific stuff.

    Quote Originally Posted by Eri523 View Post
    So in C++/CLI a pointer-to-member-function seems to be some kind of hybrid thing.
    Probably.

    Quote Originally Posted by Eri523 View Post
    Fascinating! I always thought of a pointer-to-member-function (in native C++) as a mere bundle of a pointer to the function code and a this pointer. I didn't have an idea either that they can do such fancy things. Now that I know of it it seems just logical, though. I never had a need for that yet (and an extremely rare need for pointers-to-member-functions at all except for creation of .NET delegates) but I feel the probability is high that sometime the day will come when it's good to know that...
    Another important consequence of delegates behaving this way is that you must take this behavior into account for security considerations. For example, imagine a framework that provides an extension point (not unlike Windows Forms, where you "plug-in" app-specific functionality by deriving from Form); if the imaginary framework uses a delegate internally, and this delegate points to a virtual member function, then malicious client code might cause some trouble by overriding this function in a derived class.

    Quote Originally Posted by Eri523 View Post
    I know that Smalltalk often is referred to as the flagship among the OO languages, but I think there have been some languages catching up during the last years, didn't they (whatever they are - can't think of any particular one right now)?
    Honestly, neither can I.

    Quote Originally Posted by Eri523 View Post
    If language syntax is the this interface used by developers (clients) to communicate to the compiler, then I might have some dissatisfaction with it.
    To be honest, I don't understand the sentence above. Is the word "this" in it in some way related to the this pointer (in C++) or handle (in C++/CLI)?
    Sorry, my bad - there's an extra word in that sentence. I started writing it one way, then rephrased, but obviously didn't clean up too well.
    It should've said: "If language syntax is this interface", or "If language syntax is the interface in question". So, I was referring to my previous sentence, where I said that in that particular statement I'm using the word "interface" in a very broad sense (== anything that acts as an intermediary between the client and implementation: a remote controller as an interface to the TV, a steering wheel as an interface to the car, the syntax of a programming language as an interface to the compiler, or public class members ans the interface to the class...).
    With that in mind, I was not talking of anything specific to C++ or C++/CLI, but only wanted to express my dissatisfaction with interface designs that are (if only in certain aspects) influenced too much by the internal details (while I have no problem with documenting these details so that those interested can learn about them and put the knowledge to good use; but note that implementation can be subject to change).

    Quote Originally Posted by Eri523 View Post
    [...] but wouldn't simplifying the calling syntax too much severely obscure the actual meaning of the statement?
    Maybe. Then again, when you declare it, you know what it is, especially if you give it a descriptive name. I don't know - it's probably a matter of preference.

    Quote Originally Posted by Eri523 View Post
    But applying maximum simplification would make the call via the pointer look like a direct call to a member function in the scope of the class the call is made from (hmmm, is there really no more compact term for that? ) or a global function (ignoring namespace-scope functions here that I consider to be globals anyway).
    Didn't you just describe how delegates look like when invoking the referenced functions?

    Quote Originally Posted by Eri523 View Post
    I just found this blog entry (including comments) that may interest you in this respect: http://blogs.msdn.com/b/oldnewthing/.../03/66660.aspx
    Let me reflect on a few points made there:
    Here's how the Microsoft C++ compiler manages vector allocation. Note that this is internal implementation detail, so it's subject to change at any time, but knowing this may give a better insight into why mixing scalar and vector new/delete is a bad thing.

    The important thing to note is that when you do a scalar "delete p", you are telling the compiler, "p points to a single object." [...]

    When you do "delete[] p", you are saying, "p points to a bunch of objects, but I'm not telling you how many."
    Ant to tie this to your question:

    Quote Originally Posted by Eri523 View Post
    (3) - and that's what just came to my mind right now: If the OS really shouldn't be able to provide the information about the size of the memory block, then how is the runtime supposed to determine for how many array elements to call the destructor in case of a delete []?
    From that blog - it seems that the compiler does some extra work to handle things properly. But if it does the extra work already, than it surely can infer all that it needs from the declaration/initialization, without the programmer needing to tell it: "Hi there, Compiler! Just wanted to remind you that p points to a bunch of objects, in case you've forgotten - " .
    IM(H)O, the design is made more complicated without a good reason. But, I'd like to see what were the considerations that provoked the design, maybe I'm missing something.
    Anyway, I'm talking about what could've been done, not about what things look like now. So, of course, a C++ programmer needs to use these the way they were meant to be used. Which brings me to that thread:

    Quote Originally Posted by Eri523 View Post
    I found that link in a thread in the Non-VC++ section which is dedicated to just that topic but IMO not as much to the point as the blog entry, at least not yet.
    Note how the OP read and linked to that blog article, but sort of missed the point. Which somewhat reinforces my view.

  4. #19
    Join Date
    Jan 2010
    Posts
    1,099

    Re: Event handlers vs. base class method overrides

    At that thread, the OP mentioned "The C++ Programming Language" by Bjarne Stroustrup, p. 128 - which contains a sentence that talks about the way the operators we were talking about are usually implemented:

    To deallocate space allocated by new, delete and delete [] must be able to determine the size of the object allocated. This implies that an object allocated using the standard implementation of new will occupy slightly more space than a static object. Typically, one word is used to hold the object's size.

  5. #20
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,587

    Re: Event handlers vs. base class method overrides

    Quote Originally Posted by TheGreatCthulhu View Post
    Another important consequence of delegates behaving this way is that you must take this behavior into account for security considerations. For example, imagine a framework that provides an extension point (not unlike Windows Forms, where you "plug-in" app-specific functionality by deriving from Form); if the imaginary framework uses a delegate internally, and this delegate points to a virtual member function, then malicious client code might cause some trouble by overriding this function in a derived class.
    If I saw something like that I would first assume the imaginary framework intentionally behaves like this. It is what virtual functions are made for. If I were a member of that framework's design team I would implement the virtual function as a mere call to a non-virtual member function and have the delegate point to that if I didn't want the behaviour you describe.

    If that behaviour actually was unintended then I would think there's no fundametal difference to unintentionally exposing implementation details to client code in any other language.

    [...]

    With that in mind, I was not talking of anything specific to C++ or C++/CLI, but only wanted to express my dissatisfaction with interface designs that are (if only in certain aspects) influenced too much by the internal details (while I have no problem with documenting these details so that those interested can learn about them and put the knowledge to good use; but note that implementation can be subject to change).
    Well, going back to programming (because I don't design cars or AV appliances), I must admit that I probably also at least sometimes tend to model my interfaces too close to the implementation myself. Maybe that's because I actually have the implementation details in the back of my mind when designing the interface. So it may be a good Idea, when working in a team, to task one of the members solely with interface design, at least for some time, without giving him/her insight into implementation details at that point. That probably won't completely eliminate the problem however, simply because programmers think like programmers... (I don't know whether this actually is common practice because I never worked in a team big enough to have more than one member work on a single module, interface and implementation.)

    Didn't you just describe how delegates look like when invoking the referenced functions?
    Oops! I actually have never made a call via a delegate myself yet (always had framework classes do that for me) so I was somehow assuming they had some kind of Invoke() method. They actually have (as I interpret the first Note in the Remarks section of http://msdn.microsoft.com/en-us/library/y22acf51.aspx) but also have that functionality implemented as some sort of operator() which of course is the common way of using them. So of course you're right: A call via a delegate looks like an ordinary function call unless you clarify its meaning by some naming convention.

    From that blog - it seems that the compiler does some extra work to handle things properly. But if it does the extra work already, than it surely can infer all that it needs from the declaration/initialization, without the programmer needing to tell it: "Hi there, Compiler! Just wanted to remind you that p points to a bunch of objects, in case you've forgotten - " .
    IM(H)O, the design is made more complicated without a good reason. But, I'd like to see what were the considerations that provoked the design, maybe I'm missing something.
    I agree that proably C++ could have been designed without the need for the [] versions of new and delete with negligible effort by employing the techniques presented in that blog article. Perhaps Stroustrup decided against that to give compiler developers the occasion to save a few bytes and microseconds, doing just that kind of nit-picking that was done in some of the blog comments.

    Note how the OP read and linked to that blog article, but sort of missed the point. Which somewhat reinforces my view.
    Agreed. When implementation details like that are revealed, this is thrilling stuff for curious minds like me, but the OP apparently actually wants to make use of these details in code. IMO the whole discussion is moot anyway: Why not take the natural approach and simply use an std::vector, as already suggested by some poster relatively early in that thread?

    Also, thanks for the Stroustrup quote. If I actually have that passage in my copy (I have the 3rd ed., not the special ed.) there would have been little chance I wuld've actually found it because it's the German translation. On page 128 I have 6.1.8 (A Note on Style) and 6.2 (Operator summary) and it's cetainly not in there. From what I found on Stroustrup's pages I think I can conclude, however, that it's not too far away from that page (if it's actually there).
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  6. #21
    Join Date
    Jan 2010
    Posts
    1,099

    Re: Event handlers vs. base class method overrides

    Quote Originally Posted by Eri523 View Post
    If that behaviour actually was unintended then I would think there's no fundametal difference to unintentionally exposing implementation details to client code in any other language.
    Yeah, but remember, I had no idea that delegates could do that. Maybe composition would be a better example than inheritance; but overall, now that I reflect, it was probably a not very well thought-of example altogether. In any case, it's a bad design what I was talking about, nothing really worth discussing. Just me thinking out loud about this newly discovered trait of theirs...

    Quote Originally Posted by Eri523 View Post
    Well, going back to programming (because I don't design cars or AV appliances)
    LOL, OK. But, as a side note, check out what Gamma et al. said at the start of their now famous book on Design Patterns:
    What is a Design Pattern?
    Christopher Alexander says, "Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice" [AIS+77, page x]. Even though Alexander was talking about patterns in buildings and towns, what he says is true about object-oriented design patterns. Our solutions are expressed in terms of objects and interfaces instead of walls and doors, but at the core of both kinds of patterns is a solution to a problem in a context.
    Everything's connected... (the X-Files theme playing in the background)

    Quote Originally Posted by Eri523 View Post
    I must admit that I probably also at least sometimes tend to model my interfaces too close to the implementation myself.
    Happens to everyone. Some software development methodologies suggest to design the interfaces and relations first, and the implementation later - but in an iterative way, where you adapt the software being developed according to ever increasing understanding of the problem domain, as you go along. The test-first approach goes nicely with that, too.
    However, note that sometimes an "ideal" (whatever that means) context-free design can't be implemented properly precisely because a specific implementation environment cannot support it (for example, performance would suffer) - so implementation details sometimes must affect the design to a degree.

    Quote Originally Posted by Eri523 View Post
    Also, thanks for the Stroustrup quote. If I actually have that passage in my copy (I have the 3rd ed., not the special ed.) there would have been little chance I wuld've actually found it because it's the German translation. On page 128 I have 6.1.8 (A Note on Style) and 6.2 (Operator summary) and it's cetainly not in there. From what I found on Stroustrup's pages I think I can conclude, however, that it's not too far away from that page (if it's actually there).
    Should be... 3rd ed., too: 6.2.6.1 (Arrays), just under the example, the second sentence.

  7. #22
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,587

    Re: Event handlers vs. base class method overrides

    Quote Originally Posted by TheGreatCthulhu View Post
    But, as a side note, check out what Gamma et al. said at the start of their now famous book on Design Patterns:

    [...]
    Really a great quote (containing another quote).

    A second thought on the steering wheel analogy: This is an obvious example of legacy design. When originally introduced, the steering wheel interface was highly implementation-dependent due to limitations of those day's technology. In the meantime implementation technology has considerably evolved, even frequently resulting in situations where the steering wheel interface is placed on top of an abstraction layer called drive-by-wire. That legacy interface, however, is still used in practically all implementations, primarily simply due to long-acquired habits of billions of users. There are alternative interfaces, e.g. joysticks, available that might better fit today's implementations but yet they're not accepted by the public.

    Everything's connected... (the X-Files theme playing in the background)


    Should be... 3rd ed., too: 6.2.6.1 (Arrays), just under the example, the second sentence.
    Found it, thanks. It's on page 138. However, there's a translation glitch in my copy. Translated back, it reads:

    Quote Originally Posted by Stroustrup, TC++PL 3rd ed., German translation
    To deallocate space allocated by new, new and new [] must be able to determine the size of the object allocated. This implies that an object allocated using the standard implementation of new will occupy slightly more space than a static object. Typically, one word is used to hold the object's size.
    Interestingly, just in the next paragraph he also mentions std::vector. However, I don't think he does that to contrast his "subtle" mention of implementaion details in the quoted passage and the conclusions the OP of the thread over there in the Non-VC++ section pulled from that.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Page 2 of 2 FirstFirst 12

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center