RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1559480
Accepted
Никита
Никита
Asked:2023-12-29 22:13:48 +0000 UTC2023-12-29 22:13:48 +0000 UTC 2023-12-29 22:13:48 +0000 UTC

正确的运算符重载 [] (C++)

  • 772

我面临着编写自己的关联数组并为其重载索引运算符 [] 的任务。我写的,重载看起来像这样:

template<class Key, class Data>
Data& AssociativeArray<Key, Data>::operator[](const Key& key)
{
    for (Pair& p : array)
    {
        if (p.key == key)
        {
            return p.value;
        }
    }

    // Если ключ не найден создаём новую пару
    Pair newPair = { key, Data{} };
    array.push_back(newPair);
    return array.back().value;
}

//для константного массива
template<class Key, class Data>
const Data& AssociativeArray<Key, Data>::operator[](const Key& key) const
{
    for (const Pair& p : array)
    {
        if (p.key == key)
        {
            return p.value;
        }
    }
    return Data{};
}

我认为我的问题已经很明显了:在我的实现中,我寻找一个键,如果它不存在,我用这样的键创建一个新的空元素。一方面,这很方便 - 这样我可以分配一个新值,就像常规数组一样:

Arr["newKey"] = "new value";

但另一方面,当尝试从不存在的键中获取值时

std::string str = Arr["newKey"];

它创建一个新的空的,虽然它不应该,但应该抛出一个错误。

所以问题是:我怎样才能正确地做到这一点,以便它在接收值时抛出错误,并在添加它时创建一个元素?

以防万一,这是整个类结构:

template<class Key, class Data>
class AssociativeArray
{
public:
    Data& operator[](const Key& key);
    const Data& operator[](const Key& key) const;
    template<class K, class D>
    friend std::ostream& operator<<(std::ostream& os, const AssociativeArray<K, D>& arr);

private:
    struct Pair
    {
        Key key;
        Data value;
    };
    std::vector<Pair> array;
};

template<class Key, class Data>
Data& AssociativeArray<Key, Data>::operator[](const Key& key)
{
    for (Pair& p : array)
    {
        if (p.key == key)
        {
            return p.value;
        }
    }

    // Если ключ не найден создаём новую пару
    Pair newPair = { key, Data{} };
    array.push_back(newPair);
    return array.back().value;
}

template<class Key, class Data>
const Data& AssociativeArray<Key, Data>::operator[](const Key& key) const
{
    for (const Pair& p : array)
    {
        if (p.key == key)
        {
            return p.value;
        }
    }
    return Data{};
}

template<class Key, class Data>
std::ostream& operator<<(std::ostream& os, const AssociativeArray<Key, Data>& arr)
{
    for (const auto& pair : arr.array)
    {
        os << "Key: " << pair.key << ", Value: " << pair.value << std::endl;
    }
    return os;
}
c++
  • 2 2 个回答
  • 83 Views

2 个回答

  • Voted
  1. Best Answer
    HolyBlackCat
    2023-12-30T16:01:57Z2023-12-30T16:01:57Z

    正常情况下这是不可能做到的。最接近的是[]按值返回辅助对象,并带有重载operator=和operator T。但是转换运算符不允许您像这样编写,例如:foo[42].bar()- 因此您必须添加一个函数来显式读取元素,本着foo[42].get().bar(). 但看起来不太好看。


    与其试图将两种不同的行为塞进一个[],不如只制作两个单独的函数/语句。

    Например, оставить [] для чтения (и кидать исключение если элемента нет), а для вставки - отдельную функцию.

    • 2
  2. NunOfIt
    2023-12-30T06:13:21Z2023-12-30T06:13:21Z

    作为一个选项,创建一个存储搜索结果的代理类,并为其定义赋值运算符和强制转换运算符;第一个在必要时创建一个对象,第二个抛出异常。

    关联数组.hpp

    #ifndef ASSOCIATIVE_ARRAY_HPP
    #define ASSOCIATIVE_ARRAY_HPP
    
    #define AA AssociativeArray<Key, Data>
    #define AATemplate template<class Key, class Data>
    #define AASubclassMethod(type, subclass) AATemplate type AA::subclass
    
    #include <vector>
    #include <iostream>
    
    AATemplate
    class AssociativeArray {
    public:
        class DataHolder {
            Data* value_;
    
        public:
            DataHolder();
            DataHolder(const Data&);
    
            DataHolder(DataHolder&&);
            DataHolder(const DataHolder&);
    
            DataHolder& operator=(DataHolder&&);
            DataHolder& operator=(const DataHolder&);
    
            ~DataHolder();
    
            Data& value();
            const Data& value() const;
    
            void clear();
            bool empty() const;
    
            Data& operator=(const Data&);
    
            operator bool() const;
    
            template<typename NewType> operator NewType() const;
    
            Data* operator->();
    
            Data& operator*();
            const Data& operator*() const;
    
            void swap(DataHolder&);
    
        private:
            void check_empty() const;
        };
    
        class Pair {
            Key* key_;
            DataHolder data_;
    
        public:
            Pair();
            Pair(const Key&);
            Pair(const Key&, const Data&);
    
            Pair(Pair&&);
            Pair(const Pair&);
    
            Pair& operator=(Pair&&);
            Pair& operator=(const Pair&);
    
            ~Pair();
    
            Key& key();
            const Key& key() const;
    
            Data& value();
            const Data& value() const;
    
            DataHolder& data();
            const DataHolder& data() const;
    
            void clear();
    
            void swap(Pair&);
        };
    
        bool empty() const;
        size_t size() const;
    
        DataHolder& operator[](const Key&);
        const DataHolder& operator[](const Key&) const;
    
        template<typename K, typename D>
        friend std::ostream& operator<<(std::ostream&, const AssociativeArray<K, D>&);
    
    private:
        std::vector<Pair> array;
    };
    
    /* :::::::::::::::: */
    /* DataHolder Class */
    /* :::::::::::::::: */
    
    // ---------- //
    // - public - //
    // ---------- //
    
    /* Constructors */
    
    AASubclassMethod(,DataHolder)::DataHolder(): value_(nullptr) {}
    AASubclassMethod(,DataHolder)::DataHolder(const Data& value): value_(new Data(value)) {}
    AASubclassMethod(,DataHolder)::DataHolder(const AA::DataHolder& other): AA::DataHolder::DataHolder(*other.value_) {}
    AASubclassMethod(,DataHolder)::DataHolder(AA::DataHolder&& other): AA::DataHolder::DataHolder() { other.swap(*this); }
    
    /* Assignement Operators (input: DataHolder Class) */
    
    AASubclassMethod(typename AA::DataHolder&, DataHolder)::operator=(const AA::DataHolder& other) {
        this->clear();
        value_ = new Data(*other.value);
        return *this;
    }
    
    AASubclassMethod(typename AA::DataHolder&, DataHolder)::operator=(AA::DataHolder&& other) {
        this->clear();
        other.swap(*this);
        return *this;
    }
    
    /* Destructor */
    
    AASubclassMethod(,DataHolder)::~DataHolder() { this->clear(); }
    
    /* get_value Functions */
    
    AASubclassMethod(Data&, DataHolder)::value() { return *value_; }
    AASubclassMethod(const Data&, DataHolder)::value() const { return *value_; }
    
    /* Other Functions */
    
    AASubclassMethod(bool, DataHolder)::empty() const { return bool(value_); }
    AASubclassMethod(void, DataHolder)::clear() { delete value_; value_ = nullptr; }
    
    /* Other Operators */
    
    AASubclassMethod(Data&, DataHolder)::operator=(const Data& value) {
        this->clear();
        value_ = new Data(value);
        return this->value();
    }
    
    AASubclassMethod(template<typename NewType>, DataHolder)::operator NewType() const { check_empty(); return NewType(this->value()); }
    
    AASubclassMethod(Data*, DataHolder)::operator->() { return value_; }
    AASubclassMethod(Data&, DataHolder)::operator*() { return this->value(); }
    AASubclassMethod(const Data&, DataHolder)::operator*() const { return this->value(); }
    
    AASubclassMethod(void, DataHolder)::swap(AA::DataHolder& other) { std::swap(value_, other.value_); }
    
    // ----------- //
    // - private - //
    // ----------- //
    
    AASubclassMethod(void, DataHolder)::check_empty() const {
        if(this->empty())
            throw std::runtime_error("///");
    }
    
    /* :::::::::: */
    /* Pair Class */
    /* :::::::::: */
    
    // ---------- //
    // - public - //
    // ---------- //
    
    /* Constructors */
    
    AASubclassMethod(,Pair)::Pair(): key_(nullptr) {}
    AASubclassMethod(,Pair)::Pair(const Key& key): key_(new Key(key)) {}
    AASubclassMethod(,Pair)::Pair(const Key& key, const Data& value): key_(new Key(key)), data_(value) {}
    
    AASubclassMethod(,Pair)::Pair(Pair&& other): Pair() { other.swap(*this); }
    AASubclassMethod(,Pair)::Pair(const Pair& other): Pair(other.key(), other.value()) {}
    
    /* Assignement Operators (input: Pair Class) */
    
    AASubclassMethod(typename AA::Pair&, Pair)::operator=(Pair&& other) {
        this->clear();
        other.swap(*this);
        return *this;
    }
    
    AASubclassMethod(typename AA::Pair&, Pair)::operator=(const Pair& other) {
        this->clear();
        key_ = new Key(other.key());
        data_ = AA::DataHolder(other.data());
        return *this;
    }
    
    /* Destructor */
    
    AASubclassMethod(,Pair)::~Pair() { this->clear(); }
    
    /* get_value Functions */
    
    AASubclassMethod(Key&, Pair)::key() { return *key_; }
    AASubclassMethod(const Key&, Pair)::key() const { return *key_; }
    
    AASubclassMethod(Data&, Pair)::value() { return *data_; }
    AASubclassMethod(const Data&, Pair)::value() const { return *data_; }
    
    AASubclassMethod(typename AA::DataHolder&, Pair)::data() { return data_; }
    AASubclassMethod(const typename AA::DataHolder&, Pair)::data() const { return data_; }
    
    /* Other Functions */
    
    AASubclassMethod(void, Pair)::clear() { delete key_; key_ = nullptr; data_.clear(); }
    
    AASubclassMethod(void, Pair)::swap(AA::Pair& other) {
        data_.swap(other.data_);
        std::swap(key_, other.key_);
    }
    
    /* :::::::::::::::::::::: */
    /* AssociativeArray Class */
    /* :::::::::::::::::::::: */
    
    // ---------- //
    // - public - //
    // ---------- //
    
    AATemplate bool AA::empty() const { return array.empty(); }
    AATemplate size_t AA::size() const { return array.size(); }
    
    AATemplate
    typename AA::DataHolder& AA::operator[](const Key& key) {
        for (Pair& p: array)
            if (p.key() == key) { return p.data(); }
    
        // Если ключ не найден создаём новую пару
        array.push_back(Pair(key));
        return array.back().data();
    }
    
    AATemplate
    const typename AA::DataHolder& AA::operator[](const Key& key) const {
        for (const Pair& p: array)
            if (p.key() == key) { return p.data(); }
        throw std::runtime_error("///");
    }
    
    AATemplate
    std::ostream& operator<<(std::ostream& out, const AA& arr) {
        out << '{';
        if(!arr.empty()) {
            auto print_pair = [&out, &arr](size_t idx) -> char {
                out << '{' << arr.array[idx].key() << ", ";
                out << arr.array[idx].value() << '}';
                return '\0';
            };
    
            (void) print_pair(0);
            for(size_t i = 1; i < arr.size(); ++i) 
                out << ", " << print_pair(i);
        }
        out << '}';
        return out;
    }
    
    #endif
    

    主程序

    #include <string>
    #include "AssociativeArray.hpp"
    
    int main() {
        AssociativeArray<int, std::string> arr;
    
        arr[5] = "abc";
        arr[6] = "def";
        arr[-100] = "g";
        std::cout << arr << '\n';
        std::string str = arr[6];
        return 0;
    }
    

    结论:

    {{5, abc}, {6, def}, {-100, g}}
    terminate called after throwing an instance of 'std::runtime_error'
      what():  ///
    zsh: IOT instruction  ./app
    
    • 0

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5