【问题标题】:C++ use string to call object member functionC++使用字符串调用对象成员函数
【发布时间】:2015-07-04 06:33:21
【问题描述】:

我有一个超类Entry 和子类MusicAlbumBookFilm。这些子类的实例根据项目名称存储,即Book1。所有这些实例的名称和类型都存储在向量cat_vector 中,该向量是libCatalogue 类对象的向量,它只存储名称和类型:

class libCatalogue{
    std::string name;
    std::string type;
public:
    libCatalogue(std::string name, std::string type);
    std::string getname();
    std::string gettype();
};

libCatalogue::libCatalogue(std::string name, std::string type) :name(name), type(type) {};
std::vector <libCatalogue> cat_vector;

向量中的条目是在构造函数中创建的,例如。

MusicAlbum::MusicAlbum(std::string a, std::string b, std::string borrower)
    : name(a), artist(b), Entry(borrower){
    cat_vector.push_back(libCatalogue(name, "MusicAlbum")); 

每个子类都有一个名为printdetails() 的成员函数。我想使用循环遍历cat_vector 中的每个条目并打印条目的详细信息,但以下内容不起作用:

int no = 1;
    for (auto it = begin(cat_vector); it != end(cat_vector); ++it)
    {
        std::string name_ = it->getname();
        std::string type_ = it->gettype();
        std::cout << "Entry no. " << no << std::endl;
        std::cout << "Name: " << name_ << std::endl;
        std::cout << "Type: " << type_ << std::endl << std::endl;
        if (type_ == "MusicAlbum"){
            name_.printdetails();     //print using MusicAlbum member function
        }
    //etc...
        no++;

我知道这是因为name_ 是一个字符串,而不是我要调用的任何类的对象,但到目前为止我还没有找到任何转换它的方法。有什么方法可以告诉编译器name_ 指的是其中一个子类的对象?

【问题讨论】:

  • 哪个类里面定义了print_details?
  • 不,它是std::string。包含的内容无关紧要。这听起来像libCatalogue shoudl me a std::multimap&lt;std::string, std::shared_ptr&lt;Entry&gt;&gt;,或类似的东西。我假设printdetails() 是从Entry 开始的虚拟或纯虚拟。
  • 三个子类都有自己的 printDetails

标签: c++ oop object


【解决方案1】:

C++ 是statically typedcompiled language。您不能即时创建变量。幸运的是,对于此类情况,解决方法是使用查找表。通常这是通过映射来实现的,其中键是字符串,值是您想要关联并调用特定字符串的函数。

我知道这是因为 name_ 是一个字符串,而不是任何 我想打电话的课程,但我找不到任何方法 转换它到目前为止。有没有办法告诉编译器 name_ 是 引用其中一个子类的对象?

当您限定成员时,成员名称是根据变量类型而不是内容来限定的。所以调用name_.printdetails() 意味着您正在尝试为std::string 类型的实例调用成员函数printdetails,但std::string 没有名为printdetails 的成员函数。

扩展上述思想的一个简单例子

struct Spam
{

    enum { NO_OF_FUNCTIONS = 4 };
    Spam()
    {
        lookup_callback["Foo1"] = std::bind(&Spam::foo1, this);
        lookup_callback["Foo2"] = std::bind(&Spam::foo2, this);
        lookup_callback["Foo3"] = std::bind(&Spam::foo3, this);
        lookup_callback["Foo4"] = std::bind(&Spam::foo4, this);
    }
    void foo1() { std::cout << "Foo1" << std::endl; }
    void foo2() { std::cout << "Foo2" << std::endl; }
    void foo3() { std::cout << "Foo3" << std::endl; }
    void foo4() { std::cout << "Foo4" << std::endl; }

    void call(std::string name)
    {
        if (lookup_callback.count(name) > 0)
        {
            lookup_callback[name]();
        }
        else
        {
            std::cerr << "Invalid Function Call" << std::endl;
        }
    }
    std::map<std::string, std::function<void(void)>> lookup_callback;
};
// Driver program to test above functions
int main()
{
    std::string name;
    Spam spam;
    for (std::cin >> name; name != "quit"; std::cin >> name)
    {
        spam.call(name);
    }
}

【讨论】:

  • 如果我创建了一个测试对象,例如“MA1”,那么即使我没有明确定义它是哪个成员函数,使用 MA1.printdetails 也没有问题
【解决方案2】:

如果您传递Entry 的实例,那么您将不会遇到问题,因为您将能够调用:

it->entry->print_details();

如果您不想让LibCatalogue 知道Entry 的实例,您可以创建一个名为Printable 或类似名称的新类。该课程将由EntryLibCatalogue 主持。 `Printable 类将包含打印所需的所有详细信息。这样你就可以同时调用:

it->printable->print_details();
entry->printable->print_details();

【讨论】:

    【解决方案3】:

    为了补充@abhijit 的回答,如果内容少且使用量少,我经常使用静态表格。

    // Typedef for a the function pointer
    typedef void (*Function_Pointer)(void);
    
    struct key_function_entry
    {
      const char * key_text;
      Function_Pointer function;
    };
    
    void Process_Foo1_Request(void);
    void Process_Bach_Request(void);
    void Process_Eat_Request(void);
    
    static const key_function_entry delegation_table[] =
    {
      {"foo1", Process_Foo1_Request},
      {"Bah",  Process_Bah_Request},
      {"eat",  Process_Eat_Request},
    };
    static const unsigned int delegation_entries =
      sizeof(delegation_table) / sizeof(delegation_table[0]);
    
    void Process_Request(const std::string& request)
    {
      for (unsigned int i = 0U; i < delegation_entries; ++i)
      {
        if (request == delegation_table[i].key_text)
        {
          delegation_table[i].function(); // Execute the associated function.
          break;
        }
      }
    }
    

    这里的一个优点是表是静态的(一个实例)和常量,因此可以将其放入只读内存中。该表不需要在运行时构建(如std::map)。该代码引用了在编译阶段创建的表。 (这是嵌入式系统的东西,可以节省内存或将东西放入只读内存中。)

    对于少量条目,线性搜索可能比std::map 更快。

    对于较大的条目或非常大量的访问,std::map 可能是首选。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 2018-08-26
      • 2016-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多