Полиморфизм с функцией друга в C ++ - PullRequest
1 голос
/ 13 апреля 2020

Я хотел бы объединить понятия полиморфизма и дружбы. Я делаю чисто виртуальную функцию-член базового класса другом другого класса. Затем я хотел бы переопределить эту чисто виртуальную функцию-член в классах, производных от этого базового класса, и получить доступ к закрытым данным члена класса, который имеет такую ​​функцию, как друг. Смотрите фрагмент кода ниже. Компилятор жалуется, когда я ссылаюсь на my_int в функции-члене производных классов add(). Я понимаю, что дружба - это отношения 1: 1, но мне интересно, есть ли способ обойти ее, чтобы реализовать полиморфизм. Должен ли я просто сделать функции-члены различных производных классов друзьями foo() класса?

class foo {
private:
    int my_int{};
public:
    friend virtual int base::add();
};

class base {
public:
    virtual int add() = 0;
};

class derived_1 : public base {
public:
    int add() {
        return my_int + 1;
    }
};

class derived_2 : public base {
public:
    int add() {
        return my_int + 2;
    }
}

Ответы [ 2 ]

2 голосов
/ 13 апреля 2020

Во-первых, с тем, что вы отобразили, это не сработает, потому что my_int является членом foo, но в дереве базовых классов нет 'foo', из которого можно получить член.

Простым ответом было бы заставить функцию принять аргумент int и полностью отказаться от использования друга.

struct derived2 : base
{
  int add(int arg) { return arg + 2; }
};

Использование «друга» должно заставить вас серьезно задуматься о том, то, что вы делаете, - хороший ответ, иногда ответ на этот вопрос «да», но не часто. И чем больше друзей вам нужно, тем реже ответ остается «да».

Другой способ - добавить функцию в базу:

int get_arg(foo & f) { return f.my_int; }

и сделать эту функцию другом, а не add, get_arg () вызывается из add () каждого производного, чтобы получить значение для работы, но get_arg не является виртуальным.

2 голосов
/ 13 апреля 2020

Возможно, вы захотите посмотреть здесь:

https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Friend_Function

Намерение

Имитация виртуального Функция друга.

Решение и пример кода

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

class Base {
  public:
    friend ostream& operator << (ostream& o, const Base& b);
    // ...
  protected:
    virtual void print(ostream& o) const
    { ... }
};
/* make sure to put this function into the header file */
inline std::ostream& operator<< (std::ostream& o, const Base& b)
{
  b.print(o); // delegate the work to a polymorphic member function.
  return o;
}

class Derived : public Base {
  protected:
    virtual void print(ostream& o) const
    { ... }
};
...