【问题标题】:How to expose a subset of the public interface to a class如何将公共接口的子集公开给类
【发布时间】:2010-11-03 06:49:17
【问题描述】:

我有一个类 - PluginLoader 处理另一个类 Plugin 来执行其功能。 Plugin 类使用了PluginLoader 中的一些函数。这两个类都是抽象基类,所以我不能将Plugin 声明为PluginLoader 的朋友。而且我不希望Plugin 使用的函数在PluginLoader 的公共界面中可用,因为它们与PluginLoader 的用户无关。这是个常见的问题吗?如何解决?

编辑:代码示例

class PluginLoader
{
   public:
      virtual void RegisterPlugin(Plugin*) = 0;
      virtual void RegisterFunction(int, Plugin*) = 0;
};

class Plugin
{
   public:
      virtual void Load(PluginLoader&) = 0;
}

class PlugImp : public Plugin
{
   public:
      virtual void Load(PluginLoader& oPLoader)
      {
         //Do stuff
         oPLoader.RegisterPlugin(this);
      }
}

虽然我希望RegisterPlugin 可用于Plugin 类,但让PluginLoader 类的其他用户可见是没有意义的。

EDIT2:@chubsdad

#include <iostream>

using namespace std;

class PluginLoader;
class Plugin
{
    public:
        virtual void Register(PluginLoader&) = 0;
        virtual ~Plugin() = 0;
};

class PluginLoader
{
    public:
        virtual void Load() = 0;

        virtual ~PluginLoader() = 0;

    private:
        friend class Plugin;
        virtual void RegisterPlugin(Plugin&) = 0;
};

class PluginImp : public Plugin
{
    public:
        void Register(PluginLoader& oPLoader)
        {
            oPLoader.RegisterPlugin(*this);
        }
};

class PluginLoaderImp : public PluginLoader
{
    public:
        void Load()
        {
            Plugin* pP = new PluginImp();
            pP->Register(*this);
        }

    private:
        void RegisterPlugin(Plugin& oP)
        {
            cout << "PluginLoaderImp::RegisterPlugin" << endl;
        }
};

int main()
{
    PluginLoader* pPLoader = new PluginLoaderImp();
    pPLoader->Load();
}

这会引发编译器错误:

main.cpp: In member function ‘virtual void PluginImp::Register(PluginLoader&)’:
main.cpp:22: error: ‘virtual void PluginLoader::RegisterPlugin(Plugin&)’ is private
main.cpp:30: error: within this context

这给我们带来了完整的循环。还是我缺少什么?

【问题讨论】:

    标签: c++ oop


    【解决方案1】:

    在 OP 有代码 sn-p 之前的响应

    我没有看到你指出的朋友的问题。两个抽象类可以是彼此的朋友。绝对没有问题。

    这就是我猜你的意思...(只是一个示例说明性代码)

    struct pluginloader;
    
    struct plugin{
    public:
       void publicm(pluginloader &r);
       virtual ~plugin() = 0;             // abstract
    private:
       void privatem(pluginloader &r);    // may be virtual in real code
    };
    
    struct pluginloader{
    public:
       void publicm(){};
       virtual ~pluginloader() = 0;       // abstract
    private:
       void privatem(){}                  // may be virtual in real code
       friend struct plugin;              // friend declaration
    };
    
    void plugin::publicm(pluginloader &r){
       r.privatem();                      // use private methods of pluginloader
    }
    
    void plugin::privatem(pluginloader &r){
       r.privatem();                      // use private methods of pluginloader
    }
    
    plugin::~plugin(){}
    pluginloader::~pluginloader(){}
    
    struct APlugin : plugin{
       ~APlugin(){}
    };
    
    struct ALoader : pluginloader{
       ~ALoader(){}
    };
    
    int main(){
       APlugin apl;
       ALoader ald;
    
       apl.publicm(ald);
    }
    

    【讨论】:

    • 您的示例现在有效。但是,当您从 PluginPluginInfo 派生时会发生什么?
    • 顺便说一句,我认为您的意思是 PluginLoader 而不是 PluginINfo?
    • hmm 所以friend 完全是一个编译时机制... :(。我为什么没有想到呢?
    • 是的。抽象类不能被实例化。就是这样。不影响友情机制如图
    【解决方案2】:

    假设您的PluginLoader 接口不仅仅包含Register... 方法,并且您希望通过该接口操作加载器,但在插件和加载器之间提供单独的通信通道,您可以简单地创建另一个接口PluginRegistra,也许,这将有公共的Register... 方法。

    在您的插件加载器中从它私有继承,并将Register... 方法作为加载器中的私有函数实现。没有人可以通过插件类访问Register... 方法,他们需要通过PluginRegistra 接口访问它们,并且只有加载器可以将自身转换为该类型,因为继承是私有的。

    现在只需以与现在完全相同的方式将加载程序传递给插件;插件的Load() 方法现在采用PluginRegistra 接口。不需要友谊。由于私有继承,只有插件加载器可以将自己作为PluginRegistra 的实例分发。

    根据要求提供一个示例,请注意这还没有看到编译器。

    class PluginLoader
    {
       public: 
          virtual void LoadPlugin(Plugin*) = 0;
    };
    
    class PluginRegistra
    {
       public:
          virtual void RegisterPlugin(Plugin*) = 0;
          virtual void RegisterFunction(int, Plugin*) = 0;
    };
    
    class Plugin
    {
       public:
          virtual void Load(PluginRegistra&) = 0;
    }
    
    class PlugImp : public Plugin
    {
       public:
          virtual void Load(PluginRegistra& oPLoader)
          {
             //Do stuff
             oPLoader.RegisterPlugin(this);
          }
    }
    
    class LoaderImp : public PluginLoader : private PluginRegistra
    {
       public :
          virtual void LoadPlugin(Plugin* plugin)
          {
             plugin.Load(this);
          } 
    
       private :
    
          virtual void RegisterPlugin(Plugin*) 
          {
          }
    
          virtual void RegisterFunction(int, Plugin*)
          {
          }
    }
    

    【讨论】:

    • 谁能给我详细解释一下? :( 。我试图做它看起来要求我做的事情,但没有结果。
    • 一点也不做作。从逻辑上讲,您的插件加载器有两个独立的接口,它向插件公开以允许自己注册的接口和它向世界公开的接口,因此实现它。
    • @Len Holgate:知道了。谢谢。顺便说一句,PluginLoader 应该从 IRegisterPlugins 继承 protected。否则,您无法将 this 作为 IRegisterPlugins 传递给函数。
    • 我认为私有继承应该在上面的例子中起作用,如果你有两个接口继承,你需要保护,我希望。
    【解决方案3】:

    将函数移出PluginLoader

    编辑:考虑到问题的模糊性,我或许应该提一下,您可以通过传递提供函数的对象来传递一堆相关函数作为参数。您可以从提供这些功能的类继承。以此类推。

    干杯,

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-25
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多