Thread: Calling base class function when base is a template

  1. #1
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607

    Calling base class function when base is a template

    Ran into an interesting issue last night when working on a few side projects. I have a base template class that has some virtual functions and I'm overriding one or more of them in the derived. One of them needs to call into the base class version of the function. Normally I would rename the function in the derived and then call the function in the base but in this case the name of the function for the derived fits perfectly into what it does.

    Here is the code. Names have been changed to protect the innocent.
    Code:
    template <typename ID,typename object>
    class Foo
    {
        public:
           ...
           ...
           virtual void AddRef(ID theID);
    };
    
    template <typename ID,typename object>
    void Foo<ID,object>::AddRef(ID theID)
    {
       ...
       ...
    }
    
    class Derived : public Foo<string,Object>
    {
        public:
            ...
            ...
            virtual void AddRef(string ID);
    };
    
    ...
    ...
    void Derived::AddRef(string ID)
    {
        Foo<string,Object>::AddRef(ID);
    }
    Is there a way to call the base without forcing me to type out the entire template and it's types (the bold portion of my code)? Normally I typedef this but was not sure how to do it since the class derives from the base template and specified the types during derivation. Typedef'ing Foo<string,object> in a class that derives from Foo and sets the types to string and Object feels a bit odd to me but maybe it isn't really any different than what I normally do. I'm sure typedef'ing works but is there a better way to do this?
    Last edited by VirtualAce; 07-10-2010 at 10:18 AM.

  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    *shrug*

    How portable would you like it to be? Which compilers are you targeting?

    Code:
    // GCC/SPARC/IBM but not MSVC (the ones I can test with)
    Foo::AddRef(ID); // no template "arguments"
    Code:
    // GCC/MSVC but not SPARC/IBM (the ones I can test with)
    typedef Foo<string,Object> Base;
    Base::AddRef(ID); // using typedef
    I only ask because fully specifying the name you wish to use is the only portable and reliable way to get what you want.

    [Edit]
    I realize you didn't ask, but I used to always do this by using a protected non-virtual method implementing the desired common behavior and providing a default implementation of the virtual method for forwarding behavior.
    [/Edit]

    Soma

  3. #3
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I figured the typedef would work it just felt a bit odd b/c of the derivation. But in the end I guess it is no different than typedef'ing anything else.

    I realize you didn't ask, but I used to always do this by using a protected non-virtual method implementing the desired common behavior and providing a default implementation of the virtual method for forwarding behavior.
    That is another approach that I did not think of. Thanks for the tip. My question was pretty wide open so your suggestions, whatever they may be, are more than welcomed.
    Last edited by VirtualAce; 07-10-2010 at 11:04 AM.

  4. #4
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    *tsk*

    Okay. Then I'll also offer a bit more. That method has a major problem when it hits the real world and other programmers come out to play.

    The common solution is a two stage approach where the public non-virtual interface method calls a private non-virtual implementation before calling a protected virtual method that provides the class specific behavior. This method has many of the same problems.

    These days I use a combination of the above method with "mixin" classes and "RAII" to forcibly correct and catch most of the problems. The "mixin" classes have a few virtual methods and a few implemented methods to provide the "affix" calls. The target classes specific behavior need only create an instance of a nested class provided by the "mixin" for compliance.

    *shrug*

    The implementation can get remarkably convoluted (especially if you want portability), but the compiler and linker will complain a lot if a programmer comes by and forgets to overload the target function or "apply" all the inherited behavior.

    Soma

  5. #5
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    If Foo doesn't otherwise need to be polymorphic at runtime, a possible solution may be using the CRTP here.
    Code:
    template <typename ID, typename object, typename T>
    class Foo
    {
        public:
           ...
           void AddRef(ID theID) {
               ...
               static_cast<T*>(this)->internalAddRef(theID);
               ...
           }
    };
    
    class Derived : public Foo<string, Object, Derived>
    {
        public:
            ...
            void internalAddRef(string ID) {
                ...
            }
    };
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    That's ugly, iMalc. What you're doing, if T is a derived class, is indirectly forcing the base class to rely on knowledge of the derived class. That violates the Liskov substitution principle. Regardless of how you've achieved that, such things become difficult to maintain for anyone maintaining (or, worse, deriving from) that derived class.

    Generally, I'd use the typedef approach. A derived class always knows what its base class is, so all you're quibbling over is syntax for referring to it. (I'd also std::string rather than relying on a using statement to resolve "string", but that's another story).

    If and only if, in the base class, you know that all derived classes will need to reuse the supplied behaviour, one way follows.
    Code:
    template <typename ID, typename object>
    class Foo
    {
        public:
    
           void AddRef(ID theID)
           {
               addRefBasicImplementation(theID);
               addRefOverrideableImplementation(theID);
           };
    
        protected:
    
               //   force the derived class to provide what they need
    
               virtual void addRefOverrideableImplementation(ID Theid) = 0;
    
        private:
    
               void addRefBasicImplementation(ID theID);   //  this may be inline or not, but derived classes can't change it
    };
    I've done addRefOverrideableImplementation(ID Theid) as a pure virtual function to force the derived class to override it. However, if you want it to be optional for the derived class to do that, to provide an empty body and don't make the function pure.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    That's ugly, iMalc. What you're doing, if T is a derived class, is indirectly forcing the base class to rely on knowledge of the derived class. That violates the Liskov substitution principle. Regardless of how you've achieved that, such things become difficult to maintain for anyone maintaining (or, worse, deriving from) that derived class.
    O_o

    What a bunch of trash. The "Curiously Recurring Template Pattern" is extremely well known, used in hundreds of libraries, and even used in other languages.

    Maintaining one implementation is always less difficult than maintaining multiple definitions.

    Maintaining the derived class is a non-issue; you never need do anything more than publicly or privately inherit the implementation class if the implementation class is written correctly.

    Much of well known "Boost" library could not exist without this pattern.

    Any "mixin" or "co-implementation" mechanism is ultimately impossible without this pattern.

    "LSP" only applies to "OOP". "CRTP" isn't "OOP". This is an entirely unrelated field that falls under the "Good Programming" umbrella.

    If and only if, in the base class, you know that all derived classes will need to reuse the supplied behaviour, one way follows.
    o_O

    Thanks for posting the source to what I suggested.

    Soma

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    It is ugly purely from the point of view that any cast is ugly. However it is a common technique as noted, and if you missed my brief mention of the acronym then it's easy enough to not notice the use of this pattern.

    I just threw it out there. It quite possibly doesn't suit, but it's hard to tell without more info.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    AFAIK pure virtual functions are not allowed in template classes. I'm going to go with the typedef method since it appears to be the simpler and more straightforward approach. This isn't for production code anyways and is for a side game project I'm working on with a few people. There might be a few maintaining the code but it isn't to the degree that it would be if it were being done for a company of several hundred devs so I'm not too concerned with maintenance. Plus since it is a one-shot game project I doubt I will ever see the code again.

    I appreciate all the comments and suggestions.

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by iMalc View Post
    I just threw it out there. It quite possibly doesn't suit, but it's hard to tell without more info.
    On that I agree. However, for the information available on the problem, I would suggest it is using a large implement to crack a small nut. It being a recurring pattern, does not justify using it without need. Unnecessarily doing such things tends to make things more difficult to understand, and therefore harder to maintain.

    Quote Originally Posted by Bubba View Post
    AFAIK pure virtual functions are not allowed in template classes.
    That is not true. It is true that some coding guidelines discourage virtual functions (pure or not) in template classes.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Stuck with function
    By scmurphy64 in forum C Programming
    Replies: 9
    Last Post: 11-10-2009, 11:41 AM
  2. Default class template problem
    By Elysia in forum C++ Programming
    Replies: 5
    Last Post: 07-11-2008, 08:44 AM
  3. Specialising a member function with a template template parameter
    By the4thamigo_uk in forum C++ Programming
    Replies: 10
    Last Post: 10-12-2007, 04:37 AM
  4. Message class ** Need help befor 12am tonight**
    By TransformedBG in forum C++ Programming
    Replies: 1
    Last Post: 11-29-2006, 11:03 PM
  5. Problem with Visual C++ Object-Oriented Programming Book.
    By GameGenie in forum C++ Programming
    Replies: 9
    Last Post: 08-29-2005, 11:21 PM