使用operator []时如何区分读/写操作

时间:2012-02-17 15:19:57

标签: c++

我需要编写一个带有重载operator []的类,当运算符[]用于读取或写入数据时,它具有不同的行为。 为了给出我想要实现的实际示例,假设我必须编写一个名为PhoneBook的类的实现,该类可以通过以下方式使用:

PhoneBook phoneBook(999999); // 999999 is the default number which should be
                             // used when calling someone who is not in the phone book

phoneBook["Paul"] = 234657;  // adds Paul's number
phoneBook["John"] = 340156;  // adds John's number

// next line should print Paul's number 234657
cout << "To call Paul dial " << phoneBook["Paul"] << endl;
// next line should print John's number 340156
cout << "To call John dial " << phoneBook["John"] << endl;
// next line should print 999999 because Frank is not in the phone book
cout << "To call Frank dial " << phoneBook["Frank"] << endl;

问题在于使用

phoneBook["Frank"]

我不想在Frank的电话簿中添加条目,否则基于std :: map的解决方案很容易实现。

我没有在网上找到实现这一目标的任何标准方法 经过一番思考后,我提出了以下解决方案,其中operator []返回一个名为PhoneNumber的“临时对象”。然后使用PhoneNumber来区分读/写操作:

#include <iostream>
#include <string>
#include <map>

using namespace std;

class PhoneBook{
private:
    map<string, int> data_; // stores phone numbers
    int defaultNumber_; // default number returned when no matching name is found

public:
    PhoneBook(int defaultNumber) :
        defaultNumber_(defaultNumber) {}

    // Searches in the phone book for a name. If the name is found it returns
    // the corresponding number. If the name is not found it returns defaultNumber_
    int read(string name){
        map<string, int>::iterator it = data_.find(name);
        if (it==data_.end()){
            return defaultNumber_;
        } else {
            return it->second;
        }
    }

    // Forwarding function to map operator []. It is not really necessary but it is added for clarity
    int& write(string name){
        return data_[name];
    }

    // Forward declaration of the "temporary object" returned by operator []
    // See declaration below
    class PhoneNumber;

    PhoneNumber operator[](string name){
        return PhoneNumber(this, name);
    }

    class PhoneNumber{
        friend class PhoneBook;
    private:
        PhoneBook* const phoneBook_;
        string name_;

        // Constructors are private so that PhoneNumber can be used only by PhoneBook
        // Default constructor should not be used
        PhoneNumber() :
            phoneBook_(NULL) {}

        PhoneNumber(PhoneBook* phoneBook, string name) :
            phoneBook_(phoneBook), name_(name) {}

    public:
        // conversion to int for read operations
        operator int (){
            return phoneBook_->read(name_);
            }

        // assignment operator for write operations
        const int& operator = (const int& val){
            return phoneBook_->write(name_) = val;
        }
    };
};

int main(){
    PhoneBook phoneBook(999999);

    phoneBook["Paul"] = 234657;
    phoneBook["John"] = 340156;

    cout << "To call Paul dial " << phoneBook["Paul"] << endl;
    cout << "To call John dial " << phoneBook["John"] << endl;
    cout << "To call Frank dial " << phoneBook["Frank"] << endl;

    return 0;
}

类PhoneBook的行为与我想的一样,程序打印出来:

To call Paul dial 234657
To call John dial 340156
To call Frank dial 999999

我想问你一些问题:

  1. 有没有更好的方法来获得类似我编码的类的类?
  2. 我使用的是一种技术名称,以便我可以搜索更多关于它的信息吗?
  3. 您认为我的解决方案有任何缺点/可能的改进吗?
  4. 在我正在编写的库中,启用我为PhoneBook :: operator []获取的行为 在类似的情况下非常重要,我真的很想知道你对我的问题的看法。

    谢谢!

2 个答案:

答案 0 :(得分:8)

您建议的是此问题的标准解决方案。这通常是 称为代理模式或代理习惯用语,以及您的助手类 return被称为代理。 (因为它是一个嵌套类,只需调用 它Proxy通常就足够了。)

答案 1 :(得分:-1)

我认为您可以实现两个版本的operator [],一个使用const修饰符而另一个没有。然后,如果你有一个对象说PhoneBook phoneBook(999999);,if phoneBook是const对象,只能调用operator [] const。如果phoneBook是非const对象,则调用默认operator []。如果要在给定非const对象的情况下调用operator [] const,可以添加类似static_cast<const PhoneBook&>(phoneBook)->operator[...]的强制转换。

#include <iostream>
#include <string>
#include <map>

using namespace std;

class PhoneBook{
private:
    map<string, int> data_; // stores phone numbers
    int defaultNumber_; // default number returned when no matching name is found

public:
    PhoneBook(int defaultNumber) :
        defaultNumber_(defaultNumber) {}
    int operator [] (const string& name) const
    {
        map<string, int>::const_iterator it = data_.find(name);
        if (it == data_.end())
        {
            return defaultNumber_;
        }
        else
        {
            return it->second;
        }
    }
    int& operator [] (const string& name)
    {
        return data_[name];
    }
};

int main(){
    PhoneBook phoneBook(999999);

    phoneBook["Paul"] = 234657;
    phoneBook["John"] = 340156;

    cout << "To call Paul dial " << phoneBook["Paul"] << endl;
    cout << "To call John dial " << phoneBook["John"] << endl;
    cout << "To call Frank dial " << static_cast<const PhoneBook&>(phoneBook)["Frank"] << endl;

    return 0;
}