Как вызвать реализацию частного виртуального базового класса при переопределении в дочернем классе - PullRequest
0 голосов
/ 27 сентября 2019

У меня есть иерархия классов, подобная этой:

class Base
{
public:
  void start() { init(); }
private:
  virtual void init() = 0;
};

class Default : public Base
{
private:
  virtual void init() override {/*default implementation*/};
};

class Special : public Default
{
private:
  virtual void init() override final {/*specialized implementation*/};
}

, которая работает нормально, если я вызываю start() для объекта типа Special;

Теперь у меня есть случай, когдав реализации в классе Special я хочу вызвать реализацию класса Default.Обычно это будет работать с Default::init();, но здесь произойдет сбой из-за объявления Default этого private.

Очевидно, что одним из решений является изменение этого значения с private на protected,но я хотел бы спросить, есть ли другой способ?Вместо того, чтобы позволить любому потомку вызывать эту функцию напрямую, я бы хотел ограничить это вызовами, которые инициируются через виртуальные функции, уже определенные в классе Base или Default.

Есть ли какая-либо опция илимодификатор, который позволял бы разрешать вызовы функций-членов только из дочерних классов, если они находятся внутри (одинаковых) переопределяющих виртуальных функций-членов?

1 Ответ

0 голосов
/ 27 сентября 2019

C ++ не предоставляет средств для достижения этой цели напрямую, поэтому вам придется обойти это, например, в приведенном ниже фрагменте кода.

Что ж, если вы абсолютно хотите .Лично я предпочел бы просто сделать функции защищенными, document , для чего они предназначены и когда вызываться, а затем просто доверять производным классам, чтобы все было правильно.Это, в конце концов, обеспечивает чистоту интерфейсов и не основывается на довольно необычном (и, возможно, некрасивом) паттерне (фактически передавая this дважды).

class Base
{
public:
    virtual ~Base() { }
    void start()
    {
        InitProxy p(*this);
        init(p);
    }
protected:
    class InitProxy
    {
    public:
        InitProxy(InitProxy const&) = delete;
        void init()
        {
            m_base.Base::init(*this);
        }
    private:
        friend class Base;
        Base& m_base;
        InitProxy(Base& base)
            : m_base(base)
        { }
    };
private:
    virtual void init(InitProxy& proxy) { }
};

class Derived : public Base
{
    void init(InitProxy& proxy) override
    {
        proxy.init();
    }
};

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

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