我想使用一个函数与多个私有成员变量进行交互。我想出了:
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的建议,即建议使用多个公共功能来调用单个私有功能。
答案 0 :(得分:3)
您可以使用unordered_map
来满足以下要求。
如下声明unordered_map
。
unordered_map<string, vector<int>> umap;
使用[]运算符插入要映射的值。
umap["A"] = {10,20};
umap["B"] = {30,40};
使用查找功能如下搜索unordered_map
中的键值。
string vector_name = "A";
vector_name = "A";
auto it = umap.find(vector_name);
if (it == umap.end())
return -1;
在地图中找到key,value
对后,请在int
中搜索特定的vector
,如下所示。
std::vector<int>::iterator iter = std::find(it->second.begin(), it->second.end(), 20);
如果iter
没有指向vector
端,则返回int
在vector
中的确切位置,如下所示。
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)
我必须不同意其他建议使用映射或涉及字符串的解决方案的答案。
使用字符串标识代码中的内容非常脆弱。一些主要的缺点是:没有自动完成功能,没有编译时检查。在某些情况下,您没有更好的选择(例如,在编译时不知道标识符),但这不是其中之一。
一种解决方案是给函数赋予有意义的名称。由于您提供了一个玩具示例,因此我将使用A
和B
,但在现实生活中,它们应该是有意义的名称:
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;
}
};