【问题标题】:Subclassing std::pair and std::map in C++在 C++ 中子类化 std::pair 和 std::map
【发布时间】:2013-09-01 16:37:24
【问题描述】:
    #include <iostream>
    #include <string>
    #include <utility>
    #include <map>

    using namespace std;

    class MyPair: public pair<string, int>
    {
        int _ref;
    public:
        MyPair(): pair<string, int>(), _ref(0) {}
        MyPair(string arg1, int arg2): pair<string, int>(arg1, arg2), _ref(0) {}
        ~MyPair();
        void inc() {
            _ref++;
        }
        void dec() {
            _ref--;
            if (_ref == 0) delete this;
        }
    };

    class MyMap: public map<string, int>
    {
    public:
        MyMap(): map<string, int>() {}
        MyMap(const map<string, int>& mp): map<string, int>(mp) {
            //for(auto i=begin(); i!=end(); ++i) i->inc();
            //I want to perform that instruction above, but it gives me an error
        }
        ~MyMap() {
            //for(auto i=begin(); i!=end(); i++) i->dec();
            //same as here
        }
        void insertNewPair(MyPair * mypair) {
            insert(*mypair);
            mypair->inc();
        }
    };

    int main(int argc, char **argv)
    {
        MyMap mymap;
        mymap.insertNewPair(new MyPair("1", 1));
        mymap.insertNewPair(new MyPair("2", 2));
        cout << "mymap[\"1\"] = " << mymap["1"] << endl;
        cout << "mymap[\"2\"] = " << mymap["2"] << endl;
        return 0;
    }

我从 std::pair 子类化了一个类,以便我可以在其中附加一个引用计数器。我将其命名为“MyPair”。我还从 std::map 继承,并将其命名为“MyMap”。这样每次我在 MyMap 中插入新的 MyPair 时,它都会调用 MyPair 的 inc() 成员函数,以便 MyPair 将增加其 _ref 成员,这是其引用的计数器。如果我删除 MyMap 的一个实例,它会递减它所包含的每个 MyPair 的所有 _ref 成员函数。如果 MyPair 中的 _ref 为 0,则表示不再被引用,所以会自行删除。

上面的代码有效,因为我设法在 MyMap 中注释了一些代码行。当我取消注释它们时,编译器给我一个错误,说 std::pair 没有像 inc() 和 dec() 这样的成员,即使我在 main 函数中插入了 MyPair 实例。我知道编译器没有注意到我插入了包含这些成员的 MyPair 实例,而不仅仅是一个普通的 std::pair。

有没有一种方法可以在 MyMap 中调用 MyPair(inc() 和 dec()) 的那些成员? 提前感谢您的回答。

【问题讨论】:

  • 从他们那里派生已经够糟糕的了。公开这样做是自找麻烦。
  • 试着更清楚地解释你在做什么。您只想创建一个引用的计数对。 (这 5 个词总结了你的段落)也试着清楚地表明什么不起作用。 (这里显示编译器的错误,让代码保持原样,不要注释错误)
  • 正如已经解释过这个操作系统非常糟糕的代码。我建议你阅读一些关于 C++ 的好书,比如 Effective C++、Effective STL 和其他类似的书。现代 C++ 拥有所有工具,因此没有人会编写这样的代码。

标签: c++ stdmap std-pair


【解决方案1】:

首先,inheriting from standard containers is a very bad idea

其次,我发现你的代码有很多问题:

  • 过度使用动态内存:您在完全没有理由的地方使用new。请注意,您的对是 std::string 和 int,即 每对 12 个字节,具有常见的 std::string 实现(假设 32 位架构)。 std::string 用于保存 char 数组的指针的 4 个字节,字符串的大小计数器的 4 个字节和对的 int 的 4 个字节。所以这里没有理由使用动态内存。如果您想共享所有权,请使用 smart_pointer 或 std::reference_wrapper 之类的引用包装器。

  • 根据上述问题,过度使用容易出错的原始指针。正如我所说,智能指针是更好的选择。

最后,我认为您的编译器错误是由于slicing 产生的:std::map 在内部使用std::pair 来存储值。当您插入您的配对时,该配对会被切片,因为 std::map::insertconst std::pair&amp; 视为参数,并且派生类的引用被隐式转换为基类的引用
因此,正如编译器所说,这对 (std::pair) 没有成员 inc()dec()

你继承了from std::pair,而不是std::pair继承了你的pair类。 考虑典型的继承示例:

class animal
{
    void eat();
};

class dog : public animal
{
    void bark();
};

这里的重点是狗是动物,但动物不是狗(并非所有动物都是狗)。所以狗可以吃,因为它是动物,可以吠叫,因为它是狗。 但动物不会吠叫,因为从概念上讲它不是狗
因此,如果您将狗视为动物,狗不会吠叫

【讨论】:

  • 谢谢。这是非常有用的。稍后我会按照您的建议进行操作(使用 std::reference_wrapper)。但是我认为如果我要制作自己的容器,我会让我的程序变慢,这就是为什么我选择从 std::map 子类化并利用它实现的搜索算法来查找键值。再次感谢您的帮助。
【解决方案2】:

您使用auto 发现类型(由begin 返回)是一个映射。 而且地图没有公司。 也许实现std::begin( MyMap ) 来检索正确的迭代器。

但你可能不应该派生,并且更多地包装一对。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2015-03-04
    相关资源
    最近更新 更多