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

时间:2015-01-14 21:25:36

标签: c++ pointers dictionary polymorphism

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

以下是一个例子:

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 转换为 A B C

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

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

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

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

    非常感谢任何帮助或建议。谢谢!

3 个答案:

答案 0 :(得分:1)

  1. 在基类中添加virtual成员函数以制作对象的副本。
  2. 在派生类中适当地实现它们。
  3. 在需要时调用复制功能。
  4. 这是您的代码,在适当的位置更新。

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