我有一个关于如何通过映射对识别对象的问题,实例化用该对标识的类型的对象,然后将其存储为某种类型的容器(可能是向量)。这里挂起的是我正在寻找的对象应该都是某些基类的派生类。
以下是一个例子:
class BaseClass {
public:
BaseClass() {cout << "BaseClass constructor...\n"};
~BaseClass() {cout << "BaseClass destructor...\n"};
};
class A : public BaseClass {
public:
A() {cout << "A constructor...\n"};
~A() {cout << "A destructor...\n"};
};
class B : public BaseClass {
public:
B() {cout << "B constructor...\n"};
~B() {cout << "B destructor...\n"};
};
class C : public BaseClass {
public:
C() {cout << "C constructor...\n"};
~C() {cout << "C destructor...\n"};
};
int main(int argc, char *argv[])
{
map <string, BaseClass*> my_map; // Map used to compare a string in order to identify the object type I'd like to make
vector<BaseClass*> keyword_vct; // Vector to store the objects of the different derived class types
BaseClass* ptr;
my_map.insert (make_pair ("A", ptr = new A ));
my_map.insert (make_pair ("B", ptr = new B));
my_map.insert (make_pair ("C", ptr = new C));
string testStr "B";
map <string, BaseClass*> ::const_iterator it = my_map.find(testStr);
if (it == oscards_map.end()) {
cout << "String not found in map." << endl;
}
else {
cout << it->first << "\t keyword found in map!" << endl;
BaseClass* pSomekey;
pSomekey = it->second; // This is where I'm lost
keyword_vct.push_back(pSomekey); // Once I instantiate the derived object in the line above, I want to store it in a container.
}
}
所以我的主要问题是:
如何将 pSomekey 转换为 A , B 或 C
如果我能够实例化其中一个派生类,我是否能够将这些不同类型的对象存储到同一个向量中,因为它是 BaseClass 的派生类?
我注意到当我为地图制作对时,它们似乎在各自的派生类中构造了一个对象。
我还注意到,当执行 pSomekey = it-&gt; second; 时,不会构造任何对象。
请记住,这是一个例子。在我的真实代码中,我将比较数百个 testStr 来制作数百个不同的对象。
非常感谢任何帮助或建议。谢谢!
答案 0 :(得分:1)
virtual
成员函数以制作对象的副本。这是您的代码,在适当的位置更新。
class BaseClass
{
public:
BaseClass() {cout << "BaseClass constructor...\n"};
~BaseClass() {cout << "BaseClass destructor...\n"};
virtual BaseClass* clone() const = 0;
};
class A : public BaseClass
{
public:
A() {cout << "A constructor...\n"};
~A() {cout << "A destructor...\n"};
virtual A* clone() const { return new A();}
};
class B : public BaseClass
{
public:
B() {cout << "B constructor...\n"};
~B() {cout << "B destructor...\n"};
virtual B* clone() const { return new B();}
};
class C : public BaseClass
{
public:
C() {cout << "C constructor...\n"};
~C() {cout << "C destructor...\n"};
virtual C* clone() const { return new C();}
};
int main(int argc, char *argv[])
{
map <string, BaseClass*> my_map; // Map used to compare a string in order to identify the object type I'd like to make
vector<BaseClass*> keyword_vct; // Vector to store the objects of the different derived class types
BaseClass* ptr;
my_map.insert (make_pair ("A", ptr = new A ));
my_map.insert (make_pair ("B", ptr = new B));
my_map.insert (make_pair ("C", ptr = new C));
string testStr "B";
map <string, BaseClass*> ::const_iterator it = my_map.find(testStr);
if (it == oscards_map.end()) {
cout << "String not found in map." << endl;
} else {
cout << it->first << "\t keyword found in map!" << endl;
BaseClass* pSomekey;
pSomekey = it->second;
// Make a copy of the object and store it in keyword_vct.
keyword_vct.push_back(pSomekey->clone());
}
}
答案 1 :(得分:1)
将虚拟创建函数添加到基类。
class BaseClass
{
public:
virtual BaseClass* create() const = 0;
};
class A : public BaseClass
{
public:
virtual BaseClass* create() const { return new A; }
};
class B : public BaseClass
{
public:
virtual BaseClass* create() const { return new B; }
};
// ...
keyword_vct.push_back(it->second->create());
pSomekey = it->second;
不创建任何对象的原因是您只是复制指向对象的指针,而不是对象本身。
答案 2 :(得分:0)
C ++不提供内置方式引用“类”并一般创建实例,但是,您可以自己实现它。
正如所建议的,你可以选择让实例有一个虚拟方法来创建类似于molbdnilo和R Sahu建议的类型对象。这被称为Prototype pattern
这有一个很好的优点,你可以创建“A”,“B”和“C”类型的各种对象,按照你喜欢的方式设置它们,然后通过给出它们来创建任何人的副本它们是std :: map中的一个字符串,然后在需要时调用clone方法。
但是,有一些缺点。
例如,如果“A”创建或打开了一个文件,那么虚拟“A”应创建或打开哪个文件,如果它实际上不会被使用?克隆它会创建另一个试图打开同一个文件的“A”?或者创建一个已创建的文件?
如果“A”,“B”或“C”是相当大的对象,则可以通过使用苗条工厂类来节省内存使用量,该工厂类负责构建更昂贵的对象。这样,内存仅在实际需要时使用。
如果构建“A”,“B”或“C”需要很长时间,则使用工厂可以节省时间,因为在实际需要之前不需要构建BaseClass的实例。
通常,如果派生的BaseClass类构造函数包含大的或明显的副作用(cpu,memory,io等),使用工厂可以帮助避免这些问题。
以下是如何使用Factory方法模式解决构造问题的示例。
class BaseClass
{
public:
BaseClass() { cout << "BaseClass constructor...\n"; };
~BaseClass() { cout << "BaseClass destructor...\n"; };
};
class A : public BaseClass
{
public:
A() { cout << "A constructor...\n"; };
~A() { cout << "A destructor...\n"; };
};
class B : public BaseClass
{
public:
B() { cout << "B constructor...\n"; };
~B() { cout << "B destructor...\n"; };
};
class C : public BaseClass
{
public:
C() { cout << "C constructor...\n"; };
~C() { cout << "C destructor...\n"; };
};
class BaseClassFactory
{
public:
virtual ~BaseClassFactory() {}
virtual BaseClass *create() = 0;
};
template <class T>
class BaseClassFactoryImpl : public BaseClassFactory
{
public:
BaseClass *create() override { return new T{}; }
};
int main(int argc, char *argv[])
{
map <string, BaseClassFactory*> my_map; // Map used to compare a string in order to identify the object type I'd like to make
vector<BaseClass*> keyword_vct; // Vector to store the objects of the different derived class types
BaseClass* ptr;
my_map.insert(make_pair("A", new BaseClassFactoryImpl<A>{}));
my_map.insert(make_pair("B", new BaseClassFactoryImpl<B>{}));
my_map.insert(make_pair("C", new BaseClassFactoryImpl<C>{}));
string testStr = "B";
map <string, BaseClassFactory*> ::const_iterator it = my_map.find(testStr);
if (it == my_map.end()) {
cout << "String not found in map." << endl;
}
else {
cout << it->first << "\t keyword found in map!" << endl;
BaseClass* pSomekey;
pSomekey = it->second->create(); // Here we ask the factory to create us an instance of whatever BaseClass the factory is setup to return
keyword_vct.push_back(pSomekey); // Once I instantiate the derived object in the line above, I want to store it in a container.
}
}