Thread: Class method overloading

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    141

    Class method overloading

    This has been one of my deepest forays into C++ programming, having been scared off in the past by the arcana of memory management . I 'cured' my memory management problems by incorporating garbage collection thanks to Hans Boehm. (OK I don't like writing destructors or remembering when to call them.)

    I now however have run into an interesting problem with function overloading in an inherited class.
    I have a situation that looks something like this:

    Code:
    class Foo {
    public:
    void setdims()
    {
    .....
    }
    
    void func1 ()
    {
    setdims() ;
    }
    
    } ;  /* end class Foo */
    
    class Bar: public Foo {
    public:
    void setdims()
    {
    .....  /* different implementation */
    }
    
    } ; /* end class Bar */
    I did not label setdims() as virtual since the behavior I want is for setdims to be overloaded for a class of type Bar and the Foo's setdims() to be hidden. However what happens when I call the inherited function func1() for a class of type Bar? (e.g. Bar x ; x.func1() ; ) Apparently with MS's compiler it calls Foo's setdims() and not Bar's setdims(). This is not the behavior I want. Basically I'd like to reuse Foo's code, since the only major functional change for many methods is what get's allocated in the function setdims(). Thus I'd like to call the parent's class func1() but have it call the overloaded setdims() not the parent's setdims().

    How do I fix this? Do I need the virtual descriptor here? Is this what is supposed to happen?
    Thanks in advance for your help.

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    (OK I don't like writing destructors or remembering when to call them.)
    Err . . . you shouldn't have to call destructors. They should automatically be called when a class goes out of scope or is deleted. Perhaps you meant that you don't like remembering when to delete classes.

    I did not label setdims() as virtual since the behavior I want is for setdims to be overloaded for a class of type Bar and the Foo's setdims() to be hidden.
    I think that's what virtual functions are supposed to do, isn't it?
    From an OO perspective, it is the single most important feature of C++: [6.9], [6.10].

    A virtual function allows derived classes to replace the implementation provided by the base class. The compiler makes sure the replacement is always called whenever the object in question is actually of the derived class, even if the object is accessed by a base pointer rather than a derived pointer. This allows algorithms in the base class to be replaced in the derived class, even if users don't know about the derived class.

    The derived class can either fully replace ("override") the base class member function, or the derived class can partially replace ("augment") the base class member function. The latter is accomplished by having the derived class member function call the base class member function, if desired.
    http://www.parashift.com/c++-faq-lit...functions.html

    So yes, I think you should try making Foo's setdims() virtual. (virtual functions that are overloaded automatically have "virtual" in front of them, or at least they act that way; but putting "virtual" in front of Bar's setdims() can't hurt.)
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by dwks View Post
    Err . . . you shouldn't have to call destructors. They should automatically be called when a class goes out of scope or is deleted. Perhaps you meant that you don't like remembering when to delete classes.
    Yes that's what I meant thanks, and by the way how nice it is to not have to worry about that stuff. I suppose I could have also played around with some of those smart pointer types as well to help with this, but garbage collection seems to work pretty well if you have memory to burn.

    I think that's what virtual functions are supposed to do, isn't it?

    http://www.parashift.com/c++-faq-lit...functions.html

    So yes, I think you should try making Foo's setdims() virtual. (virtual functions that are overloaded automatically have "virtual" in front of them, or at least they act that way; but putting "virtual" in front of Bar's setdims() can't hurt.)
    Yes I just tried it and you are correct, it seems to fix the problem and it even makes sense now. Moreover I don't think the virtual table overhead will be an issue for my problem either. Thanks for the help.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by SevenThunders View Post
    This has been one of my deepest forays into C++ programming, having been scared off in the past by the arcana of memory management . I 'cured' my memory management problems by incorporating garbage collection thanks to Hans Boehm. (OK I don't like writing destructors or remembering when to call them.)
    GC is a pretty hackish solution to resource management in C++, since we have containers, smart pointers, and RAII. I would hate to think that my objects might never be deleted at all, at the whim of the GC, or deleted in an order I have no control over.

    As far as overriding methods, whether you use "virtual" depends on whether you want to make calls to the objects through a pointer or reference to one of its base classes. Since you use GC, I assume you've got pointers all over the dang place, and so you probably want to be using "virtual." Polymorphism can't work without it.

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by brewbuck View Post
    GC is a pretty hackish solution to resource management in C++, since we have containers, smart pointers, and RAII. I would hate to think that my objects might never be deleted at all, at the whim of the GC, or deleted in an order I have no control over.

    As far as overriding methods, whether you use "virtual" depends on whether you want to make calls to the objects through a pointer or reference to one of its base classes. Since you use GC, I assume you've got pointers all over the dang place, and so you probably want to be using "virtual." Polymorphism can't work without it.
    I don't know why it's that hack'ish. Java, D, Haskell, O'Caml and many other useful languages use garbage collection. The only real performance hit is that it's not as memory efficient but then again memory is cheap. IMHO C++ tends to generate a lot of memory leaks, especially for beginners like me.

    I think it makes C++ a lot more pleasant to program, but then I haven't messed around with some of the smart pointer stuff yet.

  6. #6
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by SevenThunders View Post
    I don't know why it's that hack'ish. Java, D, Haskell, O'Caml and many other useful languages use garbage collection. The only real performance hit is that it's not as memory efficient but then again memory is cheap. IMHO C++ tends to generate a lot of memory leaks, especially for beginners like me.

    I think it makes C++ a lot more pleasant to program, but then I haven't messed around with some of the smart pointer stuff yet.
    One of the things I don't like about languages like Java is that they have a new keyword, but no delete. Yes, it has garbage collection, but what if I don't want to wait for something that might never happen? I also want destructors and stack based objects so I can have RAII objects...

  7. #7
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by cpjust View Post
    One of the things I don't like about languages like Java is that they have a new keyword, but no delete. Yes, it has garbage collection, but what if I don't want to wait for something that might never happen? I also want destructors and stack based objects so I can have RAII objects...
    I confess I have never even heard of RAII until now. It sounds interesting, I see how it could be useful. You are correct that in most languages where the garbage control is built in, you do not have fine control over the collector. With the Hans Boehm collector you do have control in that you can explicitly free or suspend the collector if you need a computation to run in a finite period of time etc.

    Here is some propaganda with regards to D's garbage collector.
    http://www.digitalmars.com/d/2.0/garbage.html
    I guess it's possible to control the behavior of D's collector as well to some extent.

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by SevenThunders View Post
    I don't know why it's that hack'ish. Java, D, Haskell, O'Caml and many other useful languages use garbage collection.
    I believe I qualified my statement with the words "in C++..." There are better ways to do it in C++.

    Java forces you to "new" everything, there is no such thing as an automatic variable, and it gives you no "delete" and so the only choice is GC.

    Haskell and O'Caml aren't even imperative languages so they inherently can't support a concept such as RAII -- well, at least without using those "monad" things.

    And I have no idea about D.

    GC makes sense in a lot of languages. I think C++ is not one of them.

  9. #9
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by brewbuck View Post
    I believe I qualified my statement with the words "in C++..." There are better ways to do it in C++.

    Java forces you to "new" everything, there is no such thing as an automatic variable, and it gives you no "delete" and so the only choice is GC.

    Haskell and O'Caml aren't even imperative languages so they inherently can't support a concept such as RAII -- well, at least without using those "monad" things.

    And I have no idea about D.

    GC makes sense in a lot of languages. I think C++ is not one of them.
    I know we are drifting waaaay off topic, but it is an interesting point to some extent. I think most C++ programmers would agree with you. However I still think GC has some good applications in C++. It eases the burden of writing destructors, worrying about dangling references etc. and is actually has some performance benefits when a lot of small objects are being created and destroyed. Even Microsoft has a compacting GC with it's "Managed C++", though I understand it requires a language extension.

    For memory critical applications and if real time is important, then I will concede the point.

  10. #10
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    I just can't see what's so scary about writing destructors? Most of the time, I don't even need one since I don't create many object-level pointers... but if I allocate something in the constructor, I deallocate it in the destructor.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by SevenThunders View Post
    I know we are drifting waaaay off topic, but it is an interesting point to some extent. I think most C++ programmers would agree with you. However I still think GC has some good applications in C++. It eases the burden of writing destructors, worrying about dangling references etc.
    You are basing this on that you have to do everything manually. You don't. You can use smart pointers and never worry about not freeing memory. Classes are very, very useful. RAII especially, since you can pretty much encapsulate anything and let the class worry about it.
    Got heap allocated memory? No problem. Got pesky "handles"? No problem.
    And I also think you miss the point of writing destructors and are afraid of them. You shouldn't be. A destructor should merely handle things that needs to be done when a class is destroyed. It doesn't just stoop to freeing resources.
    Say you encapsulate a file with a class. So long as the class exists, it makes sense the file exists. But when the object is destroyed, the file is closed. This is handled in the destructor. But with garbage collecting, the file might not be closed when the object is no longer used.
    I actually saw beware of GC, because it really destroys C++'s RAII concept.
    It's far better to use smart pointers.

    Quote Originally Posted by SevenThunders View Post
    Even Microsoft has a compacting GC with it's "Managed C++", though I understand it requires a language extension.
    This is also not true. "Managed C++" or the newest, C++/CLI is essentially a C++ version that is designed to work with Microsoft's .NET Framework. And it just happens that their framework has a garbage collector. That's all.

    Quote Originally Posted by SevenThunders View Post
    For memory critical applications and if real time is important, then I will concede the point.
    Again, I don't really think I would agree. If such is the case, then manual deleting at right spots would be far more efficient than a GC.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by Elysia View Post
    You are basing this on that you have to do everything manually. You don't. You can use smart pointers and never worry about not freeing memory.
    I'm not an expert but I'm not entirely sure that is correct, though I suppose it depends on the pointer. From my very surface examination of this issue your smart pointer either ends up doing some kind of reference counting or you end up auto-deleting the 'smart pointer' when it leaves scope.

    Reference counting is a poor man's garbage collector. It's much slower and it can't remove cycles. Auto-deletion after leaving scope means that you have to beware the dangling pointer bug, ie accessing memory already 'deleted'. The latter is probably easier to detect than leaks however.

    Classes are very, very useful. RAII especially, since you can pretty much encapsulate anything and let the class worry about it.
    Got heap allocated memory? No problem. Got pesky "handles"? No problem.
    I'm not arguing the utility of RAII, though at least one garbage collected language such as D already has a fairly elegant approach to this (ie the scope(exit) function).

    And I also think you miss the point of writing destructors and are afraid of them. You shouldn't be. A destructor should merely handle things that needs to be done when a class is destroyed. It doesn't just stoop to freeing resources.
    I'm not afraid, I'm just glad I don't have to write them or worry about them for now. Moreover it is plenty easy to generate memory leaks in C++ code. My applications are largely numerical and I like to overload arithmetic operators and assignment operators. The arrays require the use of new (and delete for destructors) and require copy constructors and so forth. All it takes a few reassignment of existing pointers and one can generate these problems.

    Another place where I'd hate to deal with destructors, or manual memory management in general would be the maintenance of a complex self referential data structure, say something like a digital trie, or even nodes in graph that might contain cycles.

    It's especially tricky if the data structure holds references to outside data objects. Just when do you free resources for a node in a graph or the object it contains? How can you be sure that other nodes in the graph aren't still pointing to a given node? It all requires additional infrastructure for managed memory. With a GC you don't have to worry about it all. If the node becomes unreachable it's removed.

    Again, I don't really think I would agree. If such is the case, then manual deleting at right spots would be far more efficient than a GC.
    Well you are constrained in normal programming practice where you can delete your memory unless you write your own management pool. You need to still have access to the original pointer. The allocation and freeing of a large number of small blocks consumes resources and fragments memory. A GC will simply not free those small blocks until memory becomes tighter and then they are typically freed all at once if found unreachable. A compacting GC can improve cache performance by reducing memory fragmentation. So a good modern GC can outperform normal practices with managed memory for certain applications. No doubt hand optimization can win in the end, but who has time for this?

  13. #13
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by SevenThunders View Post
    Reference counting is a poor man's garbage collector.
    You could also say a Garbage Collector is a lazy man's reference counting.

    Quote Originally Posted by SevenThunders View Post
    It's much slower and it can't remove cycles. Auto-deletion after leaving scope means that you have to beware the dangling pointer bug, ie accessing memory already 'deleted'. The latter is probably easier to detect than leaks however.
    But that's where the 'reference counting' comes in. The object isn't deleted until all references to it have gone out of scope.

  14. #14
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    The object isn't deleted until all references to it have gone out of scope.
    And could we get the report of all objects that could not be freed acording to GC at some time?

    All memory that is leaked in the regular working mode could be reported by tools like BoundsChecker. Is there a tool like this for GC?
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by SevenThunders View Post
    I'm not an expert but I'm not entirely sure that is correct, though I suppose it depends on the pointer. From my very surface examination of this issue your smart pointer either ends up doing some kind of reference counting or you end up auto-deleting the 'smart pointer' when it leaves scope.
    Untrue. Smart pointers delete the pointer when all references to it is gone.

    Quote Originally Posted by SevenThunders View Post
    Reference counting is a poor man's garbage collector. It's much slower and it can't remove cycles. Auto-deletion after leaving scope means that you have to beware the dangling pointer bug, ie accessing memory already 'deleted'. The latter is probably easier to detect than leaks however.
    No, it's not. It's much faster than a GC which has to scan through all pointers and check their ties and see if it can free them. So no, smart pointers are much faster.

    Quote Originally Posted by SevenThunders View Post
    I'm not afraid, I'm just glad I don't have to write them or worry about them for now. Moreover it is plenty easy to generate memory leaks in C++ code. My applications are largely numerical and I like to overload arithmetic operators and assignment operators. The arrays require the use of new (and delete for destructors) and require copy constructors and so forth. All it takes a few reassignment of existing pointers and one can generate these problems.

    Another place where I'd hate to deal with destructors, or manual memory management in general would be the maintenance of a complex self referential data structure, say something like a digital trie, or even nodes in graph that might contain cycles.

    It's especially tricky if the data structure holds references to outside data objects. Just when do you free resources for a node in a graph or the object it contains? How can you be sure that other nodes in the graph aren't still pointing to a given node? It all requires additional infrastructure for managed memory. With a GC you don't have to worry about it all. If the node becomes unreachable it's removed.
    No! You're going about this the wrong way! Use smart pointers to deal with the data. They will ensure that the data will only be deleted when there's no reference to them still. No problems there.
    If you avoid writing destructors, then there's something wrong. A destructor shouldn't just delete memory - screw that, but to untie the integrity of the class itself, such as the file example I mentioned. For this purpose, destructors are extremely useful. IF you can just see past the whole "memory" problem.

    Quote Originally Posted by SevenThunders View Post
    Well you are constrained in normal programming practice where you can delete your memory unless you write your own management pool. You need to still have access to the original pointer. The allocation and freeing of a large number of small blocks consumes resources and fragments memory. A GC will simply not free those small blocks until memory becomes tighter and then they are typically freed all at once if found unreachable. A compacting GC can improve cache performance by reducing memory fragmentation. So a good modern GC can outperform normal practices with managed memory for certain applications. No doubt hand optimization can win in the end, but who has time for this?
    The problem with a GC is that either it runs as another thread, in which case it needs to lock access to pointers (or a global operation), which means additional overhead each time your program accesses a pointer. Or it can run at specified intervals, blocking execution of your program while it does its work.
    And compacting has its own problems. If it moves memory around, it needs to update all pointers! Lots of work.
    It's just slower than manually freeing memory.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. calling a class method within different class method
    By alyeska in forum C++ Programming
    Replies: 5
    Last Post: 03-08-2009, 10:56 AM
  2. Windows Service class constructor and OnStart method
    By George2 in forum C# Programming
    Replies: 0
    Last Post: 04-14-2008, 07:18 AM
  3. Overloading an "External" Class?
    By Zeusbwr in forum C# Programming
    Replies: 2
    Last Post: 10-30-2005, 04:34 PM
  4. problem with sending files to a class method..
    By utoots in forum C++ Programming
    Replies: 5
    Last Post: 04-02-2003, 01:38 AM
  5. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM