如何通过映射实例化派生类中的对象

How to instantiate objects from a derived class via a map

本文关键字:对象 派生 何通过 映射 实例化      更新时间:2023-10-16

我有一个关于如何通过映射对识别对象的问题,实例化与该对标识的对象,然后将其存储为某种容器(可能是向量)。这里的问题是,我正在寻找的对象都应该是某个基类的派生类。

下面是一个示例:

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.
    }
}   

所以我的主要问题是:

  1. 如何将 pSomekey 转换为类型 ABC 的对象?

  2. 如果我能够实例化其中一个派生类,我是否能够将这些不同类型的对象存储到同一个向量中,因为它们是 BaseClass 的派生类?

我注意到,当我为地图制作对时,它们似乎在各自的派生类中构造了一个对象。

我还注意到,当执行 pSomekey = it->second; 时,不会构造任何对象。

请记住,这是一个示例。 在我的真实代码中,我将比较数百个testStr来制作数百个不同的对象。

任何帮助或建议将不胜感激。谢谢!

  1. 在基类中添加 virtual 成员函数以创建对象的副本。
  2. 在派生类中适当地实现它们。
  3. 需要时调用复制函数。

这是您的代码,在正确的位置更新。

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());
        }
    }   

将虚拟创建函数添加到基类。

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; 不创建任何对象的原因是,您只是复制指向对象的指针,而不是对象本身。

>C++不提供内置方式引用"类"并通常创建实例,但是,您可以自己实现它。

正如建议的那样,您可以选择使实例具有虚拟方法来创建类似于 molbdnilo 和 R Sahu 建议的类型化对象。 这称为原型模式

这有一个很好的优势,因为你可以创建各种类型为"A"、"B"和"C"的对象,按照你喜欢的方式设置它们,然后创建它们中的任何一个的副本,只需在你的 std::map 中给它们一个字符串,然后在需要时调用克隆方法。

但是,也有一些缺点。

例如,如果"A"创建或打开了一个文件,

那么如果虚拟"A"实际上不打算使用,它应该创建或打开哪个文件? 克隆它会创建另一个试图打开同一文件的"A"?还是创建已创建的文件?

如果"A"、"B"或"C"是相当大的对象,则可以通过使用负责构造更昂贵对象的精简工厂类来节省内存使用量。 这样,内存仅在实际需要时才使用。

如果构造"

A"、"B"或"C"需要很长时间,则使用工厂可以节省时间,因为在实际需要之前不需要构造 BaseClass 的实例。

通常,如果派生的 BaseClass 类构造函数包含较大或明显的副作用(CPU、内存、io 等),则使用工厂可以帮助避免这些问题。

下面是如何使用工厂方法模式解决构造问题的示例。

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.
  }
}