Skip navigation.

Ambassador

The Royal C++ Embassy

Posts tagged with "inheritance"

It's hidden out there!

, , ,

Abruptly starting subject; overloads are not inherited, if derived class has a method with the same name - they are hidden.
#include <iostream>

using std::cout;
using std::endl;


class X
{
public:
        int Add(int)
        {
                cout << "X::Add(int)" << endl;
                return 0;
        }
        int Add(X&)
        {
                cout << "X::Add(X&)" << endl;
                return 0;
        }
};

class D : public X
{
public:
        int Add(char)  // Hides base's Add method(s)
        {
                cout << "D::Add(char)" << endl;
                return 0;
        }
};

int main()
{
        X x;
        x.Add(x);   // OK: X::Add(X&)
        x.Add(3);   // OK: X::Add(int);
        D d;
        d.Add('c'); // OK: D::Add(char)
        d.Add(1);   // Error: overloads are hidden
        d.Add(x);   // Error: overloads are hidden
        return 0;
}

Derived classes have a bad attitude of hiding its bases' methods. It may sound weird, ugly and disturbing, but imagine otherwise; base class has changed, author decided to add another overload which has an argument type that is causing an unintentional conversion with the type you pass or by-passes your intentional conversion, for example?

If you really really want to reuse base's methods, here are tricks:
  • Use "using" declaration to explicitly declare that derived class introduces base's types and methods to its declerative region (e.g. using X::Add). This will enable all overloads in base class to be visible to callers of derived.
  • Explicitly refer to base's scope in the caller (e.g. d.X::Add(x) calls X::Add(X&))
  • Implement overloads in derived, call base's methods.
  • Templatize Derived::Add (e.g. template<typename T> int Add(T t) { return X::Add(t); } - you can specialize this as well!)

My heart beats for "using" and templatizing, although this is not the way I would prefer.

If I were to design this base class:
  • Add would be a template.
  • Since this class is designed to be a base, it could look like:
    class D;
    
    template<typename T>
    class X
    {
    public:
            template<typename U>
            int Add(U u)
            {
                    T* pt = static_cast<T*>(this);
                    // force derived class to implement AddItem for each U
                    return pt->AddItem(u);
            }
    };
    
    // char, specialization.
    template<>
    template<>
    int X<D>::Add<char>(char c)
    {
            // add it
            return 0;
    }
    

  • If it's not a template, it would probably have private pure virtual functions that needs to be implemented by derived types. (I've just heard some said "private pure virtual function? I thought we're talking about recent British-Pakistan cricket game!".)

    class X
    {
    virtual int AddChar() = 0;
    virtual int AddInt() = 0;
    // .. others
    public:
    int Add(char c)
    {
    return AddChar();
    }
    };

If I were to write derived class:
  • There will not be inheritance, but "pimpl".

    class D /* : public X */
    {
    X* m_px;
    public:
    int Add(char c)
    {
    return m_px->Add(c);
    }
    };
  • If there is an inheritance, I would use "using" to declare base's methods
  • or, alternative to above case, I would use template methods and may be their specializations.

This all depends on design.
Download Opera, the fastest and most secure browser
December 2009
S M T W T F S
November 2009January 2010
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31