在 C++ 中,基于 class 中的参数查看私有变量的访问器方法?

Accessor Method to view private variable based on argument in a class in c++?

我的问题是我的 class 中有很多变量,我希望通过访问器方法访问它们。当然,我可以有多个访问器函数来输出我的私有变量,但我该怎么做才能通过参数访问其中的任何一个。我的class:

class Character {
public:
    void setAttr(string Sname,int Shealth,int SattackLevel,int SdefenseLevel)  {
        name = Sname;
        health = Shealth;
        attackLevel = SattackLevel;
        defenseLevel = SdefenseLevel;

    }
    int outputInt(string whatToOutput)  {
        return whatToOutput //I want this to either be health, attackLevel or defenseLevel
    }

private:
    string name;
    int health;
    int attackLevel;
    int defenseLevel;
};

基本上我想知道的是如何 return 关于 outputInt 函数的私有变量。大多数 OOP 教程都有一个函数来 return 每个变量,这在大型程序中似乎是一件非常不健康的事情。

我不知道这对你来说是否是个好主意,但你可以使用通过引用传递的 public typedef 结构并设置你的值。

class Character {
public:
    //...
    typedef struct allvalues{
        string vname;
        int vhealth;
        int vattackLevel;
        int vdefenseLevel;
    }allvalues;

    void getValues(allvalues& val){
        val.vname = name;
        val.vhealth = health;
        val.vattackLevel = attackLevel;
        val.vdefenseLevel = detenseLevel;
    }

    //...
};

//...
//somewhere in the code
Character myCarac;


//...
//Here how to use it
Character::allvalues values;
myCarac.getValues(values);

C++ 不支持您尝试完成的任务:关于对象的反射或详细的运行时信息。在 C++ 中有一个叫做 "Run-Time Type Information" 的东西,但它不能提供关于你的变量名的信息:原因是因为在编译和链接的二进制文件中,这个信息(你的变量名)将不再存在。

但是,您可以使用 std::unordered_map 而不是普通整数变量来完成类似的事情。所以可以通过名称访问值,如字符串。 请考虑以下代码:

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

using namespace std;

class Character {
public:
  void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
    name = Sname;
    values.insert(std::make_pair("health", Shealth));
    values.insert(std::make_pair("attackLevel", SattackLevel));
    values.insert(std::make_pair("defenseLevel", SdefenseLevel));
  }
  int outputInt(const string& whatToOutput) {
    return values.at(whatToOutput);
  }

private:
  string name;
  std::unordered_map<std::string, int> values;
};

int main(int argc, char* argv[]) {
  Character yourCharacter;
  yourCharacter.setAttr("yourName", 10, 100, 1000);
  std::cout << "Health: " << yourCharacter.outputInt("health") <<std::endl;
  std::cout << "Attack level: " << yourCharacter.outputInt("attackLevel") << std::endl;
  std::cout << "Defense level: " << yourCharacter.outputInt("defenseLevel") << std::endl;
  return 0;
}

它将按预期输出:

Health: 10
Attack level: 100
Defense level: 1000

另一个不依赖于 unordered_map 的选项是,使用预定义的静态字符串作为变量名,使用数组或向量作为值。所以我们可以用类似的东西替换上面的 class Character

static std::string variableNames[3] = {
  "health",
  "attackLevel",
  "defenseLevel"
};

class Character {
public:
  void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
    name = Sname;
    variableValues[0] = Shealth;
    variableValues[1] = SattackLevel;
    variableValues[2] = SdefenseLevel;
  }
  int outputInt(const string& whatToOutput) {
    int retVal = 0;
    for (size_t i = 0; i < sizeof(variableNames)/sizeof(std::string); ++i) {
      if (!whatToOutput.compare(variableNames[i])) {
        retVal = variableValues[i];
      }
    }
    return retVal;
  }

private:
  string name;
  int variableValues[3];
};

并且仍然得到相同的输出。但是,在这里您必须手动管理一个列表,其中包含字符串数组中的所有变量名称 - 我不喜欢这个解决方案,个人更喜欢上面的其他解决方案之一。

C++ 中处理此类设计的最常见方法是使用单独的 getHealth()getAttackLevel()getDefenseLevel() 函数。但是这样会漏掉一个用例,就是:如果想让用户输入一个字符串,比如"health"然后显示对应的变量,就需要自己写代码调用对应的getXXX() 函数。如果这不是您的问题,请考虑以下更简洁的代码:

#include <string>
#include <iostream>

using namespace std;

class Character {
public:
  void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
    name = Sname;
    health = Shealth;
    attackLevel = SattackLevel;
    defenseLevel = SdefenseLevel;
  }
  int getHealth() const { return health; }
  int getAttackLevel() const { return attackLevel; }
  int getDefenseLevel() const { return defenseLevel; }
private:
  string name;
  int health, attackLevel, defenseLevel;
};

int main(int argc, char* argv[]) {
  Character yourCharacter;
  yourCharacter.setAttr("yourName", 10, 100, 1000);
  std::cout << "Health: " << yourCharacter.getHealth() <<std::endl;
  std::cout << "Attack level: " << yourCharacter.getAttackLevel() << std::endl;
  std::cout << "Defense level: " << yourCharacter.getDefenseLevel() << std::endl;
  return 0;
}

另一个不相关的建议:不要使用字符串作为函数的参数类型,而是使用 const string&(对字符串的常量引用;请参阅上面的示例代码)。这允许更轻松地调用您的函数(它们可以直接使用字符串文字调用,而无需在调用代码中创建额外的变量)并且它们不会进行额外的不必要的复制。然后唯一的副本将发生在:name = Sname;(在您的代码中发生了两个副本)。