Частное наследование родителя при публичном наследовании его дедушки в C ++ - PullRequest
0 голосов
/ 06 июня 2018

Название говорит об этом.Parent публично выставляет Grandparent, и я хочу, чтобы это было публично в Child, но я хочу скрыть сам Parent.Я не понимаю, почему это невозможно, но я не могу найти способ использовать директиву using для достижения этой цели.Если я смогу использовать using для публичного предоставления приватно-унаследованных переменных-членов, я ожидаю, что смогу сделать то же самое для приватно-унаследованных баз, но не могу найти синтаксис для этого.Явный оператор преобразования в Child может работать, но есть ли более чистый способ?

class Grandparent {};

class Parent: public Grandparent {};

class Child: Parent
{
  // How can I expose Grandparent here publicly?
};

void takeGrandparent( Grandparent const & );

int main()
{
  takeGrandparent( Child() ); // error: cannot cast 'Child' to its private base class 'Grandparent'
}

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

Ответы [ 4 ]

0 голосов
/ 07 июня 2018
class Grandparent {
public:
  virtual void foo() = 0;
};

class Parent: public Grandparent {
public:
  virtual void foo() final { std::cout << "Dance!\n"; }
};


template<class D>
struct proxy_Grandparent:Grandparent {
  virtual void foo() final {
    return proxy().foo();
  }
private:
  D* self() { return static_cast<D*>(this); }
  D const* self() const { return static_cast<D const*>(this); }
  decltype(auto) proxy() {
    return self()->get_proxy();
  }
};

class Child: Parent,
  public proxy_Grandparent<Child>
{
  friend class proxy_Grandparent<Child>;
private:
  Parent& get_proxy() { return *this; }
};

это имеет две копии Grandparent в нем;если Grandparent является интерфейсом, это не так уж и проблематично.

Действительно, вы должны изменить Parent наследование на полностью has-a:

class Child:
  public proxy_Grandparent<Child>
{
  friend class proxy_Grandparent<Child>;
private:
  Parent parent;
  Parent& get_proxy() { return parent; }
};
0 голосов
/ 06 июня 2018

Существует концептуальная проблема с реализацией Child в терминах Parent, но только превращение ее в Grandparent:

Это означает, что контракт Parent нарушен, что означает реализациюChild тесно зависит от особенностей реализации Parent.Мы используем абстракцию и инкапсуляцию, изолирующую нас от этих деталей по какой-то причине.

В противном случае вы могли бы просто сделать Child a Parent тоже.

Следовательно, C ++ никогда не добавлял синтаксис, позволяющийэто.

0 голосов
/ 07 июня 2018

Вы можете наследовать Grandparent также напрямую.Это требует virtual наследования, как это обычно бывает с множественным наследованием.

class Grandparent {};

class Parent: virtual public Grandparent {};

class Child: Parent, virtual public Grandparent
{
  // No special treatment needed, interface is inherited automatically
};

Это действительно имеет смысл в контексте идеи частного наследования.Вы можете думать о частном наследовании как о «мне лень добавлять Parent член к Child, поэтому вместо этого я реализую его с наследованием».Если вы делаете это «правильно» с композицией, это становится больше похоже на обычный код с делегированием:

class Grandparent
{
public:
    virtual int GrandparentMethod() {return 8;}
};

class Parent: public Grandparent {};

class Child: public Grandparent
{
public:
    virtual int GrandparentMethod() {return parent.GrandparentMethod();}

private:
    Parent parent;
};
0 голосов
/ 06 июня 2018

Нет, «чистого» пути не существует.

Публичное наследование выражает is-a связь, а private - нет.Как только вы отметили, что ваш Child не Parent, вы потеряли все претензии, заявив, что Child - Grandparent - вы разорвали цепочку транзитивности.Единственный способ установить Child как Grandparent - это также наследовать его от Grandparent - но я уверен, что вы не хотите идти по этому пути.

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