Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Plugin Abstract Interface idea

Plugin Abstract Interface idea

Scheduled Pinned Locked Moved C / C++ / MFC
questionperformancehelptutorialannouncement
9 Posts 4 Posters 3 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    saiyuk6 7
    wrote on last edited by
    #1

    I have a question i want to create a plugin manager, and i have a small example test-bed written. It has abstract classes. The function CreatePluginClass will the main function to control a set of mini classes that will use the same Interface IPlugin and create a Pointer stored into memory for the new class that will eventually have to be released, so i made a auto/release type template class to do that for me CPluginObject as you can see in the example entry main function Will this be reliable, because i kinda want to go through this type of approach and if something wrong with this can someone help me point out what it could be?, so far everything is fine that i can see but im not sure that later on that it will cause me problems, if anyone has done anything like this before. I would appreciate the helpful tips when i tested it i get the results im looking for i guess in the console output shows TestPlugin2::Function1 TestPlugin2::Function1

    #include <stdio.h>

    class IPlugin {
    public:
    virtual void Function1() = 0;
    virtual void Function2() = 0;
    };

    class TestPlugin1 : public IPlugin {
    public:
    virtual void Function1() {
    printf("TestPlugin1::Function1\n");
    }

    virtual void Function2() {
    printf("TestPlugin1::Function1\n");
    }
    };

    class TestPlugin2 : public IPlugin {
    public:
    virtual void Function1() {
    printf("TestPlugin2::Function1\n");
    }

    virtual void Function2() {
    printf("TestPlugin2::Function1\n");
    }
    };

    #define PLUGIN_CLASS_1 100
    #define PLUGIN_CLASS_2 100

    void CreatePluginClass(int iid, IPlugin **pObj)
    {
    *pObj = NULL;
    if (iid == PLUGIN_CLASS_1)
    *pObj = new TestPlugin1();
    if (iid == PLUGIN_CLASS_2)
    *pObj = new TestPlugin2();
    }

    template<int N>
    class CPluginObject {
    public:
    CPluginObject() {
    CreatePluginClass(N, &pPluginObj);
    }
    ~CPluginObject() {
    if (pPluginObj != NULL)
    delete pPluginObj;
    pPluginObj = NULL;
    }

    IPlugin *GrabObject() const {
    return pPluginObj;
    }
    protected:
    IPlugin *pPluginObj;
    };

    void main(void)
    {
    CPluginObject<PLUGIN_CLASS_1> plugin;
    IPlugin *pObj = plugin.GrabObject();

       pObj->Function1();
       pObj->Function2();
    

    }

    modified on Sunday, August 1, 2010 5:36 AM

    M A K 3 Replies Last reply
    0
    • S saiyuk6 7

      I have a question i want to create a plugin manager, and i have a small example test-bed written. It has abstract classes. The function CreatePluginClass will the main function to control a set of mini classes that will use the same Interface IPlugin and create a Pointer stored into memory for the new class that will eventually have to be released, so i made a auto/release type template class to do that for me CPluginObject as you can see in the example entry main function Will this be reliable, because i kinda want to go through this type of approach and if something wrong with this can someone help me point out what it could be?, so far everything is fine that i can see but im not sure that later on that it will cause me problems, if anyone has done anything like this before. I would appreciate the helpful tips when i tested it i get the results im looking for i guess in the console output shows TestPlugin2::Function1 TestPlugin2::Function1

      #include <stdio.h>

      class IPlugin {
      public:
      virtual void Function1() = 0;
      virtual void Function2() = 0;
      };

      class TestPlugin1 : public IPlugin {
      public:
      virtual void Function1() {
      printf("TestPlugin1::Function1\n");
      }

      virtual void Function2() {
      printf("TestPlugin1::Function1\n");
      }
      };

      class TestPlugin2 : public IPlugin {
      public:
      virtual void Function1() {
      printf("TestPlugin2::Function1\n");
      }

      virtual void Function2() {
      printf("TestPlugin2::Function1\n");
      }
      };

      #define PLUGIN_CLASS_1 100
      #define PLUGIN_CLASS_2 100

      void CreatePluginClass(int iid, IPlugin **pObj)
      {
      *pObj = NULL;
      if (iid == PLUGIN_CLASS_1)
      *pObj = new TestPlugin1();
      if (iid == PLUGIN_CLASS_2)
      *pObj = new TestPlugin2();
      }

      template<int N>
      class CPluginObject {
      public:
      CPluginObject() {
      CreatePluginClass(N, &pPluginObj);
      }
      ~CPluginObject() {
      if (pPluginObj != NULL)
      delete pPluginObj;
      pPluginObj = NULL;
      }

      IPlugin *GrabObject() const {
      return pPluginObj;
      }
      protected:
      IPlugin *pPluginObj;
      };

      void main(void)
      {
      CPluginObject<PLUGIN_CLASS_1> plugin;
      IPlugin *pObj = plugin.GrabObject();

         pObj->Function1();
         pObj->Function2();
      

      }

      modified on Sunday, August 1, 2010 5:36 AM

      M Offline
      M Offline
      Moak
      wrote on last edited by
      #2

      Hi, I suggest to simplify. :) There is no need to mix templates, virtual methods and a global factory function. Wouldn't it be simpler to let polymorphism do the work, inherit from the plugin interface and that's it. This works because virtual methods Function1()/Function2() will be called in the specific implementation (even when called via base class pointer IPlugin). The problem with plugins is typically memory handling, at least that is the first thing that comes in my mind. You need to make sure that dynamic memory allocation/deallocation happens in the same heap (STL strings and containers can't be used out-of-the-box). Of course, you can use allocators to get better control of memory allocation/deallocation over library boundaries. There is also a nice book called Imperfect C++ which describes these kind of problems and possible solutions. Not sure if I answered your questions, but I hope I could give some help. /M PS: There is a typo TestPlugin1::Function2() and TestPlugin2::Function2() in the printf text string, that's why the debug output is other than expected.

      Chat in Europe :java: Now with 24% more Twitter

      S 1 Reply Last reply
      0
      • S saiyuk6 7

        I have a question i want to create a plugin manager, and i have a small example test-bed written. It has abstract classes. The function CreatePluginClass will the main function to control a set of mini classes that will use the same Interface IPlugin and create a Pointer stored into memory for the new class that will eventually have to be released, so i made a auto/release type template class to do that for me CPluginObject as you can see in the example entry main function Will this be reliable, because i kinda want to go through this type of approach and if something wrong with this can someone help me point out what it could be?, so far everything is fine that i can see but im not sure that later on that it will cause me problems, if anyone has done anything like this before. I would appreciate the helpful tips when i tested it i get the results im looking for i guess in the console output shows TestPlugin2::Function1 TestPlugin2::Function1

        #include <stdio.h>

        class IPlugin {
        public:
        virtual void Function1() = 0;
        virtual void Function2() = 0;
        };

        class TestPlugin1 : public IPlugin {
        public:
        virtual void Function1() {
        printf("TestPlugin1::Function1\n");
        }

        virtual void Function2() {
        printf("TestPlugin1::Function1\n");
        }
        };

        class TestPlugin2 : public IPlugin {
        public:
        virtual void Function1() {
        printf("TestPlugin2::Function1\n");
        }

        virtual void Function2() {
        printf("TestPlugin2::Function1\n");
        }
        };

        #define PLUGIN_CLASS_1 100
        #define PLUGIN_CLASS_2 100

        void CreatePluginClass(int iid, IPlugin **pObj)
        {
        *pObj = NULL;
        if (iid == PLUGIN_CLASS_1)
        *pObj = new TestPlugin1();
        if (iid == PLUGIN_CLASS_2)
        *pObj = new TestPlugin2();
        }

        template<int N>
        class CPluginObject {
        public:
        CPluginObject() {
        CreatePluginClass(N, &pPluginObj);
        }
        ~CPluginObject() {
        if (pPluginObj != NULL)
        delete pPluginObj;
        pPluginObj = NULL;
        }

        IPlugin *GrabObject() const {
        return pPluginObj;
        }
        protected:
        IPlugin *pPluginObj;
        };

        void main(void)
        {
        CPluginObject<PLUGIN_CLASS_1> plugin;
        IPlugin *pObj = plugin.GrabObject();

           pObj->Function1();
           pObj->Function2();
        

        }

        modified on Sunday, August 1, 2010 5:36 AM

        A Offline
        A Offline
        Aescleal
        wrote on last edited by
        #3

        First of all why are you bothering to cook your own smart pointer class for this lot? Use std::unique_ptr or std::shared_ptr. Then when you've done that you can use the smart pointer to return objects from factory functions so you don't have to worry about pointers-to-pointers and all the attendent exception safety issues. For a plugin I can't see any mention of how you'd dynamically load the plugin - without that all you've got is a baroque implementation of the factory method design pattern. When you want to create an object based on a plugin you need a way to find the executable with the plugin (which will have to be loaded from a configuration file), load it and then create an instance of the class you want created. One way of doing that is to map class name against the name of a shared library which has a known entry point:

        std::shared_ptr create_object()
        {
        return std::shared_ptr( new plugin_implementation );
        }

        that gets called after the plugin is loaded. One thing to consider is that you'll have to use the same compiler AND build settings to create the plugins and host program. Otherwise strangeness with different runtime library implementations will sink you. Provided you keep the compiler the same you can use whatever types you like in the interface. Cheers, Ash

        S 1 Reply Last reply
        0
        • A Aescleal

          First of all why are you bothering to cook your own smart pointer class for this lot? Use std::unique_ptr or std::shared_ptr. Then when you've done that you can use the smart pointer to return objects from factory functions so you don't have to worry about pointers-to-pointers and all the attendent exception safety issues. For a plugin I can't see any mention of how you'd dynamically load the plugin - without that all you've got is a baroque implementation of the factory method design pattern. When you want to create an object based on a plugin you need a way to find the executable with the plugin (which will have to be loaded from a configuration file), load it and then create an instance of the class you want created. One way of doing that is to map class name against the name of a shared library which has a known entry point:

          std::shared_ptr create_object()
          {
          return std::shared_ptr( new plugin_implementation );
          }

          that gets called after the plugin is loaded. One thing to consider is that you'll have to use the same compiler AND build settings to create the plugins and host program. Otherwise strangeness with different runtime library implementations will sink you. Provided you keep the compiler the same you can use whatever types you like in the interface. Cheers, Ash

          S Offline
          S Offline
          saiyuk6 7
          wrote on last edited by
          #4

          I took your advice. Hopefully i executed it correctly, here is the updated snippet. I still use CPluginObject template with the std::shared_ptr implementation because it looks better to type CPluginObject<num> than CreatePluginClass(num, classPtr) or would this be bad development schematics?

          typedef std::shared_ptr<IPlugin> IPluginPtr;

          void CreatePluginClass(int iid, IPluginPtr &pObj)
          {
          if (iid == PLUGIN_CLASS_1)
          pObj = IPluginPtr(new TestPlugin1());
          if (iid == PLUGIN_CLASS_2)
          pObj = IPluginPtr(new TestPlugin2());
          }

          template<int N>
          class CPluginObject {
          public:
          CPluginObject() {
          CreatePluginClass(N, pPluginObj);
          }
          IPluginPtr GrabObject() {
          return std::dynamic_pointer_cast<IPlugin>(pPluginObj);
          }
          protected:
          IPluginPtr pPluginObj;
          };

          void main(void)
          {
          CPluginObject<PLUGIN_CLASS_1> plugin;
          IPluginPtr pObj = plugin.GrabObject();

             pObj->Function1();
             pObj->Function2();
          

          }

          Eventually i want to use std::map so i dont always have to create pObj for calling other classes.

          IPluginPtr GrabObject(std::string strImp)
          {
          if (m_ClassManager.count[strImp])
          return std::dynamic_pointer_cast<IPlugin>(m_ClassManager[strImp]);
          }

          and to call the class

          GrabObject("TestClass1")->Function1();
          GrabObject("TestClass1")->Function2();

          well something in the sorts of this

          modified on Sunday, August 1, 2010 2:58 PM

          A 1 Reply Last reply
          0
          • M Moak

            Hi, I suggest to simplify. :) There is no need to mix templates, virtual methods and a global factory function. Wouldn't it be simpler to let polymorphism do the work, inherit from the plugin interface and that's it. This works because virtual methods Function1()/Function2() will be called in the specific implementation (even when called via base class pointer IPlugin). The problem with plugins is typically memory handling, at least that is the first thing that comes in my mind. You need to make sure that dynamic memory allocation/deallocation happens in the same heap (STL strings and containers can't be used out-of-the-box). Of course, you can use allocators to get better control of memory allocation/deallocation over library boundaries. There is also a nice book called Imperfect C++ which describes these kind of problems and possible solutions. Not sure if I answered your questions, but I hope I could give some help. /M PS: There is a typo TestPlugin1::Function2() and TestPlugin2::Function2() in the printf text string, that's why the debug output is other than expected.

            Chat in Europe :java: Now with 24% more Twitter

            S Offline
            S Offline
            saiyuk6 7
            wrote on last edited by
            #5

            I shall take a look at the Polymorphism, i had planned on eventually making a large class factory. I wanted to implement a hash library. example

            class IHashAlgo {
            public:
            virtual void Init() = 0;
            virtual void Update(PBYTE pData, INT nLength) = 0;
            virtual void Final() = 0;
            virtual void GetResults(PBYTE pData) = 0;
            };

            Abstract Class 1, would be MD5, the results would be the digest Abstract Class 2, would be SHA1 ..... etc I wanted to make a cleaner class library because it got really ugly when i was doing this I hope you understand what i am trying to describe at least

            class CHashAlgo {
            public:
            void Init(INT nType) {
            m_Type = nType;
            switch (nType) {
            case HASHTYPE_MD5:
            MD5Init(&m_md5);
            break;
            case HASHTYPE_SHA1:
            SHA1Init(&m_sha1);
            break;
            default:
            break;
            }
            }
            void Update(PBYTE pData, INT nLength) {
            switch (nType) {
            case HASHTYPE_MD5:
            MD5Update(&m_md5, pData, nLength);
            break;
            case HASHTYPE_SHA1:
            SHA1Update(&m_sha1, pData, nLength);
            break;
            default:
            break;
            }
            }
            void Final() {
            switch (nType) {
            case HASHTYPE_MD5:
            MD5Final(&m_md5);
            break;
            case HASHTYPE_SHA1:
            SHA1Final(&m_sha1);
            break;
            default:
            break;
            }
            }
            void GetResults(PBYTE pData) {
            switch (nType) {
            case HASHTYPE_MD5:
            memcpy(pData, m_md5.digest, MD5_DIGEST_SIZE);
            break;
            case HASHTYPE_SHA1:
            memcpy(pData, m_sha1.digest, SHA1_DIGEST_SIZE);
            break;
            default:
            break;
            }
            }
            int m_Type;
            MD5_CONTEXT m_md5;
            SHA1_CONTEXT m_sha1;
            };

            A 1 Reply Last reply
            0
            • S saiyuk6 7

              I took your advice. Hopefully i executed it correctly, here is the updated snippet. I still use CPluginObject template with the std::shared_ptr implementation because it looks better to type CPluginObject<num> than CreatePluginClass(num, classPtr) or would this be bad development schematics?

              typedef std::shared_ptr<IPlugin> IPluginPtr;

              void CreatePluginClass(int iid, IPluginPtr &pObj)
              {
              if (iid == PLUGIN_CLASS_1)
              pObj = IPluginPtr(new TestPlugin1());
              if (iid == PLUGIN_CLASS_2)
              pObj = IPluginPtr(new TestPlugin2());
              }

              template<int N>
              class CPluginObject {
              public:
              CPluginObject() {
              CreatePluginClass(N, pPluginObj);
              }
              IPluginPtr GrabObject() {
              return std::dynamic_pointer_cast<IPlugin>(pPluginObj);
              }
              protected:
              IPluginPtr pPluginObj;
              };

              void main(void)
              {
              CPluginObject<PLUGIN_CLASS_1> plugin;
              IPluginPtr pObj = plugin.GrabObject();

                 pObj->Function1();
                 pObj->Function2();
              

              }

              Eventually i want to use std::map so i dont always have to create pObj for calling other classes.

              IPluginPtr GrabObject(std::string strImp)
              {
              if (m_ClassManager.count[strImp])
              return std::dynamic_pointer_cast<IPlugin>(m_ClassManager[strImp]);
              }

              and to call the class

              GrabObject("TestClass1")->Function1();
              GrabObject("TestClass1")->Function2();

              well something in the sorts of this

              modified on Sunday, August 1, 2010 2:58 PM

              A Offline
              A Offline
              Aescleal
              wrote on last edited by
              #6

              Why don't you want to return a shared_ptr by value? What do you think you gain by default constructing an object and then overwriting its value? I'm not sure I see the logic to it as it makes the client code more complicated and it's less efficient. Have a google for NRVO and RVO - they're two optimisations that are allowed to change the observable behaviour of a program by eliminating copy constructor calls around the creation of temporary objects. If you do that you'll see that they can eliminate a copy constructor call and a destructor call when you write a function when you write your code in the form:

              A do_something()
              {
              }

              compared to:

              void do_something( A &a )
              {
              }

              I'm still missing the reason why what you're doing needs to be a plugin - from what I can see you're just trying to implement a factory that's bound to one of a fixed number of possibilities at compile time. Cheers, Ash

              1 Reply Last reply
              0
              • S saiyuk6 7

                I shall take a look at the Polymorphism, i had planned on eventually making a large class factory. I wanted to implement a hash library. example

                class IHashAlgo {
                public:
                virtual void Init() = 0;
                virtual void Update(PBYTE pData, INT nLength) = 0;
                virtual void Final() = 0;
                virtual void GetResults(PBYTE pData) = 0;
                };

                Abstract Class 1, would be MD5, the results would be the digest Abstract Class 2, would be SHA1 ..... etc I wanted to make a cleaner class library because it got really ugly when i was doing this I hope you understand what i am trying to describe at least

                class CHashAlgo {
                public:
                void Init(INT nType) {
                m_Type = nType;
                switch (nType) {
                case HASHTYPE_MD5:
                MD5Init(&m_md5);
                break;
                case HASHTYPE_SHA1:
                SHA1Init(&m_sha1);
                break;
                default:
                break;
                }
                }
                void Update(PBYTE pData, INT nLength) {
                switch (nType) {
                case HASHTYPE_MD5:
                MD5Update(&m_md5, pData, nLength);
                break;
                case HASHTYPE_SHA1:
                SHA1Update(&m_sha1, pData, nLength);
                break;
                default:
                break;
                }
                }
                void Final() {
                switch (nType) {
                case HASHTYPE_MD5:
                MD5Final(&m_md5);
                break;
                case HASHTYPE_SHA1:
                SHA1Final(&m_sha1);
                break;
                default:
                break;
                }
                }
                void GetResults(PBYTE pData) {
                switch (nType) {
                case HASHTYPE_MD5:
                memcpy(pData, m_md5.digest, MD5_DIGEST_SIZE);
                break;
                case HASHTYPE_SHA1:
                memcpy(pData, m_sha1.digest, SHA1_DIGEST_SIZE);
                break;
                default:
                break;
                }
                }
                int m_Type;
                MD5_CONTEXT m_md5;
                SHA1_CONTEXT m_sha1;
                };

                A Offline
                A Offline
                Aescleal
                wrote on last edited by
                #7

                Hi, I think most experienced C++ programmers would get what you're trying to do. You're trying to handle hashing without worrying which algorithm for hashing is bound to higher level functions. So for composing a digital signature you need a digest (hashing) algorithm and a public key signing algorithm. So to create a digital signature you'd compose a hash and a signer:

                class digest_generator
                {
                public:
                signer( hasher &h, signer &s ) : h_( h ), s_( s )
                {
                }

                    std::string create\_digest\_for\_stream( std::istream &str )
                    {
                        return s\_.signature\_of\_string( h\_.hash\_of\_stream( str ) );
                    }
                
                private:
                    hasher &h\_;
                    signer &s\_;
                

                };

                where hasher and signer are interfaces implemented by things like MD5_hasher, SHA1_hasher and RSA_signer. The question is why you need a plugin for this sort of thing. While it may sound cool to have an externally implementable interface to do security stuff you open yourself up for attack by giving attackers a way of replacing or modifying parts of your code. Anyway, think very carefully before letting other people modify the way your code works in a security context. It can bite you very hard and cause a lot of damage to your reputation. Cheers, Ash

                1 Reply Last reply
                0
                • S saiyuk6 7

                  I have a question i want to create a plugin manager, and i have a small example test-bed written. It has abstract classes. The function CreatePluginClass will the main function to control a set of mini classes that will use the same Interface IPlugin and create a Pointer stored into memory for the new class that will eventually have to be released, so i made a auto/release type template class to do that for me CPluginObject as you can see in the example entry main function Will this be reliable, because i kinda want to go through this type of approach and if something wrong with this can someone help me point out what it could be?, so far everything is fine that i can see but im not sure that later on that it will cause me problems, if anyone has done anything like this before. I would appreciate the helpful tips when i tested it i get the results im looking for i guess in the console output shows TestPlugin2::Function1 TestPlugin2::Function1

                  #include <stdio.h>

                  class IPlugin {
                  public:
                  virtual void Function1() = 0;
                  virtual void Function2() = 0;
                  };

                  class TestPlugin1 : public IPlugin {
                  public:
                  virtual void Function1() {
                  printf("TestPlugin1::Function1\n");
                  }

                  virtual void Function2() {
                  printf("TestPlugin1::Function1\n");
                  }
                  };

                  class TestPlugin2 : public IPlugin {
                  public:
                  virtual void Function1() {
                  printf("TestPlugin2::Function1\n");
                  }

                  virtual void Function2() {
                  printf("TestPlugin2::Function1\n");
                  }
                  };

                  #define PLUGIN_CLASS_1 100
                  #define PLUGIN_CLASS_2 100

                  void CreatePluginClass(int iid, IPlugin **pObj)
                  {
                  *pObj = NULL;
                  if (iid == PLUGIN_CLASS_1)
                  *pObj = new TestPlugin1();
                  if (iid == PLUGIN_CLASS_2)
                  *pObj = new TestPlugin2();
                  }

                  template<int N>
                  class CPluginObject {
                  public:
                  CPluginObject() {
                  CreatePluginClass(N, &pPluginObj);
                  }
                  ~CPluginObject() {
                  if (pPluginObj != NULL)
                  delete pPluginObj;
                  pPluginObj = NULL;
                  }

                  IPlugin *GrabObject() const {
                  return pPluginObj;
                  }
                  protected:
                  IPlugin *pPluginObj;
                  };

                  void main(void)
                  {
                  CPluginObject<PLUGIN_CLASS_1> plugin;
                  IPlugin *pObj = plugin.GrabObject();

                     pObj->Function1();
                     pObj->Function2();
                  

                  }

                  modified on Sunday, August 1, 2010 5:36 AM

                  K Offline
                  K Offline
                  KarstenK
                  wrote on last edited by
                  #8

                  Did you read this: virtual void Function2() { printf("TestPlugin2::Function1\n"); } Press F1 for help or google it. Greetings from Germany

                  S 1 Reply Last reply
                  0
                  • K KarstenK

                    Did you read this: virtual void Function2() { printf("TestPlugin2::Function1\n"); } Press F1 for help or google it. Greetings from Germany

                    S Offline
                    S Offline
                    saiyuk6 7
                    wrote on last edited by
                    #9

                    ya i know, it was a copy and paste from the first function. it was just something a small test

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups