2017-03-15 3 views
0

내 C++ 코드베이스에 플러그인 기능을 추가하려고합니다. 플러그인 작성자가 알아서는 안되는 배관을 플러그인에 포함해야하므로 (따라서 포함 파일을 간단하게 유지해야하기 때문에) 어려움이 발생합니다. 그럼이 설정입니다.플러그인이 기본 클래스에서 상속하는 C++ 플러그인 시스템

"PluginBase.h". 이것은 플러그인이 상속하는 클래스입니다.

class PluginBase { 
    virtual void PluginProcess() = 0; // the plugin-specific capability 
}; 

"PluginPlumbing.h" 배관이 들어있는 클래스입니다.

class PluginPlumbing : public PluginBase { 
    void PlumbingFunction() { 
    // Some stuff 
    PluginProcess(); 
    // Some more stuff 
    } 
}; 

(DLL을로드하여/플러그인 때문에) 그것을() PlumbingFunction를 PluginPlumbing 클래스 인스턴스에 대한 포인터를 취득하고 부를 것이다 외부 프레임 워크 코드.

그러나 필자가 가진 수수께끼는 PluginPlumbing에서 실제로 상속받지 않는 PluginPlumbing 포인터에 DLL에서 가져온 PluginBase 포인터를 업 캐스트 할 수 없다는 것입니다. 그리고 나는 PluginPlumbing으로부터 Plugin을 상속받을 수 없다. 왜냐하면 Plugin 작가에게 배관을 노출시키는 제곱에 돌아 왔기 때문이다.

내가 상상할 수있는 유일한 해결책은 멋지게 상속하는 대신 PluginBase와 PluginPlumbing이 완전히 별개의 클래스라는 것입니다. PluginBase는 DLL/so에 의해 인스턴스화 될 것이고, PluginPlumbing 인스턴스는 프레임 워크에 의해 인스턴스화 될 것이고, PluginBase 포인터를 전달하여 배관 호출을 할 수있다. 그것에 대해 갈 유일한 해결책입니까?

답변

0

플러그인의 일부 기능을 외부 소프트웨어에 노출하려면 해당 인터페이스를 제공해야합니다.

예제에서 PluginProcess() 인터페이스와 함께 PluginBase 인터페이스를 제공 했으므로 PluginBase 인터페이스의 다른 사용자는 구현을 신경 쓰지 않고도이 인터페이스를 호출 할 수 있습니다.

다른 방법으로 다른 인터페이스가 필요한 경우에도 마찬가지입니다.

class PluginPlumbing { 
public: 
    virtual void PlumbingFunction() = 0; 
}; 

그리고 당신의 DLL 구현에 구현 숨기기가 추가 매개 변수를 필요로하는 경우

class PluginPlumbingImpl : public PluginPlumbing { 
public: 
    void PlumbingFunction() override { 
     // do the stuff 
    } 
} 

을 - 또한 인터페이스 클래스 또는 POD 구조를 추상적으로 전달합니다. 인터페이스 구현을위한 정확한 인스턴스를 생성하는 플러그인 함수에 대한 선언이 있어야합니다 (플러그인 사용자가 액세스 할 수 있어야 함). 그런

이를 요약하면, 당신이해야 뭔가 :

// myplugininterface.h 
// this header will be exposed to plugin implementors and 
// plugin consumers 

class IMyPluginClass1 { 
public: 
    virtual void func1() = 0; 
    virtual void func2() = 0; 
} 

// another interface, ties together other functionality 
class IMyPluginClass2 { 
public: 
    virtual void func1() = 0; 
    // you can even pass around your interface classes 
    virtual void doSomethingWithAnotherObject(IMyPluginClass1 *obj) = 0; 

    // or use "factory" methods to create objects 
    virtual IMyPluginClass1 *createObject() = 0; 
} 

// this is functions implemented by a plugins, they should create 
// instances for your plugin objects 
// you could do them as a static methods of your classes if you don't 
// plan to expose that as C compatible plugins 
IMyPluginClass1 *createObject1(); 
IMyPluginClass2 *createObject2(); 


// mycoolplugin.cpp 
// specific implementation of your plugin, you or someone else 
// compile this to plugin DLL 

#include "myplugininterface.h" 

class IMyPluginClass1Impl : public IMyPluginClass1 { 
public: 
    IMyPluginClass1Impl() : 
     myMyValue(100500) 
    {} 

    void func1() override { 
     // implement 
    } 
    void func2() override { 
     // implement 
    } 
private: 
    // you can have any private or even public members in your implementation 
    int mMyValue; 
}; 

class IMyPluginClass2Impl : public IMyPluginClass2 { 
public: 
    void func1() override { 
     // implement 
    } 

    void doSomethingWithAnotherObject(IMyPluginClass1 *obj) override { 
     // implement 
     // but don't assume you can cast IMyPluginClass1 to 
     // something specific, because it might be not yours implementation 
     // it depends on how carefully you design your interfaces and 
     // explain to plugin writers what is allowed and what is not 
    } 

    IMyPluginClass1 *createObject() { 
     // be careful with that, in that case you MUST declare 
     // virtual destructor as a part of your interface class 
     return new IMyPluginClass1Impl(); 
    } 
}; 

IMyPluginClass1 *createObject1() { 
    return new IMyPluginClass1Impl(); 
} 
IMyPluginClass2 *createObject2() { 
    return new IMyPluginClass2Impl(); 
} 

그리고 플러그인의 사용자는 myplugininterface.hcreate 기능의 주소를 얻는 를 포함하여 사용할 수 있습니다 (이 플랫폼에 따라 다릅니다). 당신이 사용자 인터페이스 클래스에 대한 가상 소멸자를 선언해야합니다 -

new에 의해 만들어진 인스턴스를 반환하고 그렇게 만든 delete 객체로 플러그인의 사용자를 허용하는 경우 있음을 명심하십시오.

이것은 일반적인 접근 방법입니다. 플러그인 객체의 계층 구조를 가질 때 몇 가지 함정이 있습니다. 추가 작업을하지 않고도 클래스의 공통 구현을 공유 할 수 없습니다 (copypasta를 갖고 싶지 않다고 가정)