Как открыть подмножество открытого интерфейса для класса - PullRequest
3 голосов
/ 03 ноября 2010

У меня есть класс - 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

Что дает нам полный круг. Или мне чего-то не хватает?

Ответы [ 3 ]

2 голосов
/ 03 ноября 2010

Ответ ДО того, как в OP был фрагмент кода

Я не вижу проблемы с друзьями, на которую вы указываете. Два абстрактных класса могут быть друзьями друг друга. В этом нет абсолютно никакой проблемы.

Вот что, по-моему, вы указываете ... (просто пример иллюстративного кода)

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);
}
1 голос
/ 03 ноября 2010

Предполагая, что ваш интерфейс 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*)
      {
      }
}
1 голос
/ 03 ноября 2010

Переместите функции из PluginLoader.

РЕДАКТИРОВАТЬ : учитывая неопределенность вопроса, я, возможно, должен упомянуть, что вы можете передать несколько связанных функций как аргумент, передавобъект, который обеспечивает функции.И вы можете наследовать от класса, который предоставляет функции.И так далее.

Приветствия & hth.,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...