在公共成员函数调用中引用私有成员变量的更安全方法?

时间:2018-09-15 20:47:33

标签: c++ class stdvector

我想使用一个函数与多个私有成员变量进行交互。我想出了:

class Some_Vectors {

public:
  int is_value_in_vector(string vector_name, int value);
  void append_value_to_vector(string vector_name, int value)

private:
  vector<int> A;
  vector<int> B;

};


// returns value's index if it's there, -1 if not
int Some_Vectors::is_value_in_vector(string vector_name, int value) {

  vector<int> *selected_vector;

  if (vector_name == "A") {selected_vector = &A;}
  else if (vector_name == "B") {selected_vector = &B;}

  for (int i = 0; i < selected_vector->size(); i++){
    if (selected_vector[0][i] == value){
      return i;
    }
  }
  return -1;
}

它可以工作,但是我觉得比较这样的字符串不安全/脆弱。有没有一种方法可以在函数调用中专门引用私有变量?

编辑为(希望)主观性较差的问题。我最后使用了RichardCritten的建议,即建议使用多个公共功能来调用单个私有功能。

3 个答案:

答案 0 :(得分:3)

您可以使用unordered_map来满足以下要求。

  1. 如下声明unordered_map

    unordered_map<string, vector<int>> umap;
    
  2. 使用[]运算符插入要映射的值。

    umap["A"] = {10,20}; 
    umap["B"] = {30,40};
    
  3. 使用查找功能如下搜索unordered_map中的键值。

    string vector_name = "A";
    
    vector_name = "A";
    
    
    auto it = umap.find(vector_name);
    if (it == umap.end())
        return -1;
    
  4. 在地图中找到key,value对后,请在int中搜索特定的vector,如下所示。

    std::vector<int>::iterator iter = std::find(it->second.begin(), it->second.end(), 20);
    
  5. 如果iter没有指向vector端,则返回intvector中的确切位置,如下所示。

    if ( iter !=  it->second.end())
        return std::distance(it->second.begin(),iter);
    else
        return -1;
    

您的完整示例代码如下所示。

int main() 
{ 

    unordered_map<string, vector<int>> umap; 

    // inserting values by using [] operator 
    umap["A"] = {10,20}; 
    umap["B"] = {30,40}; 


    string vector_name = "A"; 

    vector_name = "A"; 


    auto it = umap.find(vector_name);
    if (it == umap.end())
    return -1;

    std::vector<int>::iterator iter = std::find(it->second.begin(), it->second.end(), 20);

    if ( iter !=  it->second.end())
     return std::distance(it->second.begin(),iter);
    else
    return -1;

} 

答案 1 :(得分:2)

我必须不同意其他建议使用映射或涉及字符串的解决方案的答案。

使用字符串标识代码中的内容非常脆弱。一些主要的缺点是:没有自动完成功能,没有编译时检查。在某些情况下,您没有更好的选择(例如,在编译时不知道标识符),但这不是其中之一。

一种解决方案是给函数赋予有意义的名称。由于您提供了一个玩具示例,因此我将使用AB,但在现实生活中,它们应该是有意义的名称:

class X
{
    public:
    auto foo_a(int value) { return foo(A, value); }
    auto foo_b(int value) { return foo(B, value); }

private:
    int foo(std::vector<int>& v, int value) { return 24; }

    std::vector<int> A;
    std::vector<int> B;
};

如果要使用一个带有参数的函数选择向量,则应选择带有枚举的向量。这样,您就具有自动完成功能和编译时的安全性(除非向后弯曲,否则您不能传递无效的选择器(就像使用字符串一样)-

class Y
{
public:
    enum class Selector { A, B };

    auto foo(Selector selector, int value) { return foo(getVector(selector), value); }

private:
    std::vector<int>& getVector(Selector selector)
    {
        switch (selector)
        {
            case Selector::A:
                return A;
            case Selector::B:
                return B;
        }
    }

    int foo(std::vector<int>& v, int value) { return 24; }

    std::vector<int> A;
    std::vector<int> B;
};
Y y{};

y.foo(Y::Selector::A, 11);
y.foo(Y::Selector::B, 1024);

答案 2 :(得分:1)

首先,如果您可以使用C ++ 17或更高版本的编译器,则最现代,最可取的可选返回方式是使用 std::optional

关于您的问题,正如@Dai在评论中提到的,最好的方法是(恕我直言)也使用

std::unordered_map<std::string, std::vector</*type*/>>

作为成员变量,您可以执行以下操作。 See Live here

#include <vector>
#include <string>
#include <unordered_map>
#include <iostream>

using uMapType = std::unordered_map<std::string, std::vector<int>>;
class MyClass
{
private:
   uMapType _vecMap;
public:
  explicit MyClass(const uMapType& vecMap): _vecMap(std::move(vecMap)) {}

  int getValue(const std::string &vector_name, const int value)const
  {
     // std::unordered_map::find the key(vector name)
     auto getVec = _vecMap.find(vector_name);
     if(getVec != _vecMap.cend())   // if iterator not pointing to map's end
     {
        const std::vector<int> &selected_vector = getVec->second;
        for (std::size_t i = 0; i < selected_vector.size(); ++i)
           if (selected_vector[i] == value)
              return i;
     }
     return -1; 
  }
};


int main()
{
    MyClass obj(
    {
        {"A", {1, 2, 3, 4, 5}},
        {"B", {1, 2, 3, 4, 5}}
    });

    std::cout << obj.getValue("A", 3) << std::endl; // output: 2
    std::cout << obj.getValue("B", 5) << std::endl; // output: 5
    std::cout << obj.getValue("C", 3) << std::endl; // output: -1
    std::cout << obj.getValue("A", 0) << std::endl; // output: -1
    return 0;
}

std::optional示例解决方案如下所示。

#include <optional>

using uMapType = std::unordered_map<std::string, std::vector<int>>;
class MyClass
{
private:
   uMapType _vecMap;
public:
  explicit MyClass(const uMapType& vecMap): _vecMap(std::move(vecMap)) {}

  std::optional<int> getValue(const std::string &vector_name, const int value)const
  {
      if(auto getVec = _vecMap.find(vector_name); getVec != _vecMap.cend())
      {
          for (std::size_t i = 0; i < getVec->second.size(); ++i)
            if (getVec->second[i] == value)
                return i;
      }
      return std::nullopt;
  }
};