Filip Frącz
Filip Frącz

Reputation: 5947

What is wrong with this inheritance?

I just don't get it. Tried on VC++ 2008 and G++ 4.3.2

#include <map>


class A : public std::multimap<int, bool>
{
public:
    size_type erase(int k, bool v)
    {
        return erase(k); // <- this fails; had to change to __super::erase(k)
    }
};

int main()
{
    A a;
    a.erase(0, false);
    a.erase(0); // <- fails. can't find base class' function?!

    return 0;
}

Upvotes: 4

Views: 2252

Answers (9)

Andy Balaam
Andy Balaam

Reputation: 6651

I agree with others' comments that you need to be very careful inheriting from STL classes, and it should almost always be avoided.

However, this problem could arise with some other base class from which it's perfectly sensible to inherit.

My question is: why not give your 2-argument function a different name? If it takes different arguments, presumably it has a slightly different meaning? E.g. erase_if_true or erase_and_delete or whatever the bool means.

Upvotes: 1

Zan Lynx
Zan Lynx

Reputation: 54325

To replace __super in a portable way, define a typedef at the top of your class like this:

typedef std::multimap<int, bool> parent;
public:
    size_type erase(int k, bool v)
    {
            return parent::erase(k);
    }

It does not need to be "parent" of course. It could be any name you like, as long as it is used consistently throughout your project.

Upvotes: 0

luke
luke

Reputation: 37443

Others have answered how to resolve the syntax problem and why it can be dangerous to derive from standard classes, but it's also worth pointing out:

Prefer composition to inheritance.

I doubt you mean for 'A' to explicitly have the "is-a" relationship to multimap< int, bool >. C++ Coding Standards by Sutter/Alexandrescu has entire chapter on this (#34), and Google points to many good references on the subject.

It appears there is a SO thread on the topic as well.

Upvotes: 3

bradtgmurray
bradtgmurray

Reputation: 14303

For those that use Effective C++ as a C++ programming reference, this issue is covered in Item 33 (Avoid hiding inherited names.) in the book.

Upvotes: 1

Enno
Enno

Reputation: 1862

Think whether you really want to inherit from std::map. In all the time I've written code, and that's longer than STL exists, I've never seen an instance where inheriting from a std::container was the best solution.

Specifically, ask yourself whether your class IS a multimap or HAS a multimap.

Upvotes: 5

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247919

1: You need to be extremely careful when deriving from C++ standard library containers. It can be done, but because they don't have virtual destructors and other such niceties, it is usually the wrong approach.

2: Overload rules are a bit quirky here. The compiler first looks in the derived class, and if it finds any overload with the same name, it stops looking there. It only looks in the base class if no overloads were found in the derived class.

A simple solution to that is to introduce the functions you need from the base class into the derived class' namespace:

class A : public std::multimap<int, bool>
{
public:
        using std::multimap<int, bool>::erase; // Any erase function found in the base class should be injected into the derived class namespace as well
        size_type erase(int k, bool v)
        {
                return erase(k);
        }
};

Alternatively, of course, you could simply write a small helper function in the derived class redirecting to the base class function

Upvotes: 18

Marcin
Marcin

Reputation: 12590

First of all, you should never derive from STL containers, because no STL containers define a virtual destructor.
Second of all, see Greg's answer about inheritance.

Upvotes: 6

J Francis
J Francis

Reputation: 1388

You've hidden the base class's erase member function by defining a function in the derived class with the same name but different arguments.

http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

Upvotes: 9

Greg Hewgill
Greg Hewgill

Reputation: 992947

When you declare a function in a class with the same name but different signature from a superclass, then the name resolution rules state that the compiler should stop looking for the function you are trying to call once it finds the first match. After finding the function by name, then it applies the overload resolution rules.

So what is happening is the compiler finds your implementation of erase(int, bool) when you call erase(0), and then decides that the arguments don't match.

Upvotes: 26

Related Questions