C ++使用string来调用对象成员函数

时间:2015-04-25 16:55:37

标签: c++ oop object

我有一个超类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_是指一个子类的对象?

3 个答案:

答案 0 :(得分:4)

C ++是statically typed compiled 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);
    }
}

答案 1 :(得分:0)

如果您传递Entry的实例,那么您将无法解决问题,因为您可以致电:

it->entry->print_details();

如果您不希望LibCatalogue知道Entry的实例,您可以创建一个名为Printable的新类或类似内容。本课程将由EntryLibCatalogue举行。 `Printable类将具有打印所需的所有细节。这样你可以同时打电话:

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

答案 2 :(得分:0)

为了增加@ 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