c ++ - Почему требуется вызов вложенного унаследованного абстрактного конструктора? [Дубликат]

Вы должны сделать что-то вроде этого:

GridLayout gridLayout = new GridLayout(this);
gridLayout.setColumnCount(2);
gridLayout.setRowCount(4);
18
задан Richard Chambers 26 April 2018 в 18:46
поделиться

3 ответа

Поскольку это позволяет избежать этого:

class A {
public:
    A(int) {}
};

class B0: virtual public A {
public:
    B0(): A(0) {}
};

class B1: virtual public A {
public:
    B1(): A(1) {}
};

class C: public B0, public B1 {
public:
    C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
25
ответ дан Oktalist 15 August 2018 в 18:51
поделиться
  • 1
    Известная проблема алмазов – CinCout 2 June 2017 в 08:54
  • 2
    Это не было бы единственной возможной двусмысленностью с множественным наследованием, и компилятор мог бы обнаружить ее одинаково хорошо. Поэтому аргумент не убедителен. – Peter A. Schneider 2 June 2017 в 14:02
  • 3
    @ PeterA.Schneider Компилятор не смог обнаружить его, если один из конструкторов был определен в другой единицы перевода. Также обнаружение - это не то же самое, что фиксация. Как бы вы устранили двусмысленность в этом примере, если вы не могли изменить B0 или B1? – Oktalist 2 June 2017 в 14:37
  • 4
    @ PeterA.Schneider давайте предположим, что вам не требуется C, чтобы определить, как он конструирует A в некоторых случаях, где вы рисуете линию? когда есть только одна база? только когда B0 и B1 используют значения constexpr, которые являются одинаковыми значениями? только когда B0 и B1 используют один и тот же литерал? – Caleth 2 June 2017 в 14:42
  • 5
    @Oktalist True на обоих учетных записях ... Я нашел проблему похожей на неоднозначные вызовы функций родительского класса. Но функции являются частью объявления класса, а реализация для ctors - нет, поэтому правильно: компилятор обычно не видит их. И это правда, что нет никакой языковой конструкции для выбора одной из инициализаций над другой (в отличие от вызова функции, который не сглаживается с помощью разрешения области). – Peter A. Schneider 2 June 2017 в 14:43

Поскольку в иерархии классов, имеющей фактически унаследованный базовый класс, базовый класс будет / может делиться несколькими классами (например, в наследовании алмаза, где один и тот же базовый класс наследуется несколькими классами). Это означает, что будет только одна копия фактически унаследованного базового класса. По сути, это означает, что базовый класс должен быть построен первым. В конечном итоге это означает, что производный класс должен создать экземпляр заданного базового класса.

Например:

class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.
7
ответ дан Ajay 15 August 2018 в 18:51
поделиться
  • 1
    Общий объект базового класса (типа A здесь) должен быть фактически создан последним (перед самым производным объектом, то есть, но после его других объектов базового класса типа B1 и B2). – Peter A. Schneider 2 June 2017 в 14:04

Я нахожу это правило ошибочным и громоздким (но тогда какая часть множественного наследования отсутствует?).

Но логически наложенный порядок построения должен отличаться от случая нормального (не- -виртуальное) наследование. Рассмотрим пример Ajay, минус virtual:

class A;
class B1 : A;
class B2 : A;
class C: B1,B2

В этом случае для каждого C два As построены, один из них является частью конструкции B1, а другой - частью конструкции B2. Код класса B отвечает за это и может это сделать. Порядок событий:

Start C ctor
   Start B1 ctor
      A ctor (in B's ctor code)
   End B1 ctor
   Start B2 ctor
      A ctor (in B's ctor code)
   End B2 ctor
End C ctor

Теперь рассмотрим виртуальное наследование в

class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 

. Один порядок события -

Start C ctor
   Start B1 ctor
      // NO A ctor
   End B1 ctor
   Start B2 ctor
      // NO A ctor
   End B2 ctor

   A ctor // not B's code!
End C ctor

Возможно, что A строится до B1 и B2, но это не имеет значения. Важно то, что конструкция А не происходит при построении других базовых классов. Этот код просто не выполняется и не может быть выполнен, потому что фактически унаследованный под-объект базового класса типа A является частью и под управлением самого производного класса , который недоступен из B1 и Код B2; действительно, C даже не полностью сконструирован в момент времени B1 или B2, и он может потенциально попытаться создать A в C.

4
ответ дан Peter A. Schneider 15 August 2018 в 18:51
поделиться
  • 1
    Здесь A не вызывается ни из B1, ни из B2, а из C, но, как вы упомянули, если A является конструктором после B1 и B2, и если конструкторы B1 и B2 используют любые переменные A, какова будет ситуация ?. Я думаю, что А сначала должен быть построен, а затем остальные. Просьба уточнить – infinite loop 15 August 2017 в 15:09
  • 2
    @infiniteloop Звучит разумно. Это действительно означает, что виртуальная база должна быть построена до любого из полученных членов. – Peter A. Schneider 18 August 2017 в 00:50
Другие вопросы по тегам:

Похожие вопросы: