使用类成员变量作为参考

Using class member variable as reference

本文关键字:参考 变量 成员      更新时间:2023-10-16

我想拥有一个类成员变量,以便能够在地图中的项目之间切换,以便在修改它后,也会修改地图的内容。

除了使用指针指向地图内容外,还有什么其他方法?旧代码仅需要变量,现在新代码需要切换。如果我更改了变量类型,则需要更改使用此成员变量的所有函数。并不复杂,但是我会发现到处都有 *……

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

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

分配了参考,您将无法重新创建参考

据我了解,您正在重构一些仅使用单个向量的现有代码,而现在您需要一个向量的地图。

您正在尝试通过最小的修改来实现这一目标,并保持与向量的接口相同。

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

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

您可以写一些包装器:

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