我有一个超类Entry
和子类MusicAlbum
,Book
和Film
。根据项目的名称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_
是指一个子类的对象?
答案 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
的新类或类似内容。本课程将由Entry
和LibCatalogue
举行。 `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
。