使用类成员变量作为参考

时间:2017-09-06 20:24:18

标签: c++ reference stdmap

我希望有一个类成员变量,以便能够在地图中的项之间切换,以便在修改时,还会修改地图的内容。

除了使用指向地图内容的指针之外,还有其他方法吗?旧代码只需要变量,现在新代码需要切换。如果我更改变量类型,则需要更改使用此成员变量的所有函数。并不复杂,但我觉得在它前面*到处都是丑陋的......

参考变量无法反弹,那么我该如何实现呢?

class A
{
    std::map<std::string,std::vector<int>> mMyMap;
    std::vector<int>& mCurrentVector;
    std::vector<int>* mCurrentVectorPointer;
    std::vector<int> mDefaultVector;

    void setCurrentVector(int iKey);
    void addToCurrentVector(int iValue);
}


A::A():
mDefaultVector(std::vector<int>())
mCurrentVector(mDefaultVector)
{
    mMyMap["key1"] = std::vector<int>(1,1);
    mMyMap["key2"] = std::vector<int>(1,2);
    mCurrentVectorPointer = &mMyMap[0];
}

A::setCurrentVector(std::string iKey)
{
    if(mMyMap.find(iKey) != mMyMap.end())
    {
        mCurrentVector = mMyMap[iKey]; //can't change a reference...
        mCurrentVectorPointer = &mMyMap[iKey]; //could use pointer, but
    }
}

A::addToCurrentVector(int iValue)
{
    mCurrentVector.push_back(iValue);
    //or
    (*mCurrentVectorPointer).push_back(iValue);
    //
    mCurrentVectorPointer->push_back(iValue);
}


void main()
{
    A wClassA();
    wClassA.setCurrentVector("key2");
    wClassA.addToCurrentVector(3);
    wClassA.setCurrentVector("key1");
    wClassA.addToCurrentVector(4);
}

mMyMap [“key1”]现在包含1,4

mMyMap [“key2”]现在包含2,3

2 个答案:

答案 0 :(得分:0)

分配后,您无法重新设置引用,这意味着您可以使用其他选项(指针)。

据我所知,你正在重构一些只使用单个向量的现有代码,而现在需要一个向量映射。

您尝试通过最少的修改来实现此目的,并保持与矢量的接口相同。

一个选项是使用从指针分配的本地引用

class A
{
    using Vector = std::vector<int>;
public:
    A()
    {
        map_["key1"] = std::vector<int>(1,1);
        map_["key2"] = std::vector<int>(1,2);
        curr_vec_ = &map_["key1"];
    }

    void setCurrentVector(const std::string& key)
    {
        if(map_.find(key) != map_.end())
        {
            curr_vec_ = &map_[key]; 
        }
    }

    void addToCurrentVector(int val)
    {
        assert(curr_vec_);
        Vector& curr_vec = *curr_vec_; // local reference

        curr_vec.push_back(val);

        curr_vec[0] = 2;
        // etc
    }

private:
    std::map<std::string, Vector> map_;
    Vector* curr_vec_ = nullptr;
}

答案 1 :(得分:0)

你可以写一些包装器:

#define Return(X) noexcept(noexcept(X)) -> decltype(X) { return X; }


template <typename U>
class MyVectorRef
{
private:
    std::vector<U>* vec = nullptr;
public:
    explicit MyVectorRef(std::vector<U>& v) : vec(&v) {}

    void reset(std::vector<U>& v) {vec = &v;}

    // vector interface
    auto at(std::size_t i) const Return(vec->at(i))
    auto at(std::size_t i)  Return(vec->at(i))
    auto operator [](std::size_t i) const Return(vec->operator[](i))
    auto operator [](std::size_t i) Return(vec->operator[](i))

    template <typename ... Ts> auto assign(Ts&&... ts) Return(vec->assign(std::forward<Ts>(ts)...))
    auto assign( std::initializer_list<U> ilist ) Return(vec->assign(ilist))
    template <typename T> auto push_back(T&& t) const Return(vec->push_back(std::forward<T>(t)))
    template <typename T> auto emplace_back(T&& t) const Return(vec->emplace_back(std::forward<T>(t)))

    auto begin() const Return(vec->begin())
    auto begin() Return(vec->begin())
    auto end() const Return(vec->end())
    auto end() Return(vec->end())
    auto cbegin() const Return(vec->cbegin())
    auto cend() const Return(vec->cend())
    // ...
};

然后,使用它:

class A
{
public:
    A() : mCurrentVector(mDefaultVector) {
        mMyMap["key1"] = std::vector<int>(1,1);
        mMyMap["key2"] = std::vector<int>(1,2);
    }

    std::map<std::string, std::vector<int>> mMyMap;
    std::vector<int> mDefaultVector;
    MyVectorRef<int> mCurrentVector;

    void setCurrentVector(std::string iKey)
    {
        auto it = mMyMap.find(iKey);
        if (it != mMyMap.end())
        {
            mCurrentVector.reset(it->second);
        }
    }
    void addToCurrentVector(int iValue)
    {
        mCurrentVector.push_back(iValue);
    }

};

但我认为在A中创建一个getter并直接使用指针会更简单:

class A
{
public:
    A() : mCurrentVector(&mDefaultVector) {
        mMyMap["key1"] = std::vector<int>(1,1);
        mMyMap["key2"] = std::vector<int>(1,2);
    }

    std::map<std::string, std::vector<int>> mMyMap;
    std::vector<int> mDefaultVector;
    std::vector<int>* mCurrentVector;

    std::vector<int>& GeCurrentVector() { return *mCurrentVector; }

    void setCurrentVector(std::string iKey)
    {
        auto it = mMyMap.find(iKey);
        if (it != mMyMap.end())
        {
            mCurrentVector = &it->second;
        }
    }
    void addToCurrentVector(int iValue)
    {
        GeCurrentVector().push_back(iValue);
    }

};