这个继承有什么问题?

时间:2008-11-11 18:09:34

标签: c++ templates

我只是不明白。试用VC ++ 2008和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;
}

9 个答案:

答案 0 :(得分:26)

当您在类中声明一个具有相同名称但与超类不同的签名的函数时,名称解析规则指出编译器应停止查找以查找您尝试调用的函数它找到了第一场比赛。按名称找到函数后,然后它将应用重载决策规则。

所以当你调用erase(int, bool)时,编译器会找到你erase(0)的实现,然后判断参数不匹配。

答案 1 :(得分:17)

1:从C ++标准库容器派生时,您需要非常小心。它可以做到,但因为它们没有虚拟析构函数和其他类似的细节,所以通常是错误的方法。

2:重载规则在这里有点古怪。编译器首先查找派生类,如果它找到具有相同名称的任何重载,它将停止查找。如果在派生类中没有找到重载,它只在基类中查找。

一个简单的解决方案是将您需要的函数从基类引入派生类的命名空间:

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);
        }
};

或者,当然,您可以简单地在派生类中编写一个小辅助函数,重定向到基类函数

答案 2 :(得分:9)

您通过在派生类中定义具有相同名称但不同参数的函数来隐藏基类的擦除成员函数。

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

答案 3 :(得分:6)

首先,您永远不应该从STL容器派生,因为没有STL容器定义虚拟析构函数。
其次,请参阅Greg关于继承的答案。

答案 4 :(得分:5)

想想你是否真的想继承std :: map。在我编写代码的过程中,这比STL更长,我从未见过从std :: container继承的实例是最佳解决方案。

具体来说,问问自己,您的班级是多图,还是 HAS 是多图。

答案 5 :(得分:3)

其他人已经回答了如何解决语法问题以及为什么从标准类派生可能会很危险,但也值得指出:

首选合成继承。

我怀疑你是否意味着“A”明确地将“is-a”关系与multimap&lt; int,bool&gt;。 Sutter / Alexandrescu的C++ Coding Standards有关于此的全部章节(#34),以及关于这一主题的Google points to many good references

似乎有SO thread on the topic as well

答案 6 :(得分:1)

对于那些使用Effective C++作为C ++编程参考的人,本书中的第33项(避免隐藏继承的名称。)中介绍了这个问题。

答案 7 :(得分:1)

我同意其他人的意见,你需要非常小心地从STL类继承,并且几乎总是应该避免。

但是,这个问题可能会出现在其他基类中,从而继承它是完全合理的。

我的问题是:为什么不给你的2参数函数一个不同的名字?如果它采用不同的论点,可能它的含义略有不同?例如。 erase_if_true或erase_and_delete或bool的意思。

答案 8 :(得分:0)

要以便携方式替换__super,请在类的顶部定义一个typedef,如下所示:

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

当然不需要是“父母”。它可以是您喜欢的任何名称,只要它在整个项目中一致使用。