2

Я знаю о физическом и виртуальном наследовании на C++. Тем не менее, я хотел бы знать, может ли эта модель каким-то образом быть достигнута с помощью любых шаблонов дизайна или трюков.Ограничение совместного использования объектов виртуальных базовых классов в C++

Классы E и F и их основания не должны изменяться. Представьте, что они получены из библиотеки extern.

Все ниже E и F открыто. Было бы хорошо, чтобы ввести промежуточные классы, помогающие функции, не являющиеся членами, шаблоны ... все, что бы понять это:

  BaseClass 
     /  \ 
     /  \ 
     A   A 
     /\  /\ 
    / \  / \ 
     B  C  B  D 
     \ /  \ /
     \/  \/
     E   F 
      \  /
      \  /
      \ /
      FinalClass 

Обратите внимание, что E и F не должна делить А. FinalClass действительно должен содержать 2 А. Моя проблема в том, что создание E или F потребует, чтобы B, C и D наследовали A практически .. однако, если A является виртуальным базовым классом, тогда компилятор создаст только один объект A в FinalClass вместо двух разные.

Итак, я думаю, что многие из вас порекомендуют композицию вместо наследования здесь. Тем не менее, композиция моделирует «имеет» -соединение здесь, а не «является» -связыванием. В объяснении я хотел бы, чтобы FinalClass действительно вел себя как E или F, включая возможность конвертировать его в эти классы.

+0

Можете ли вы создать шаблон 'A'? – curiousguy

+0

Предположим, что смогу. Что бы это изменило? Класс B также должен был бы решить, какую специализацию A он хотел бы наследовать. –

+0

Если вы можете изменить имена классов (шаблон - это просто способ изменить имена классов), вы можете решить свои ограничения 'template class B : public virtual A {' ​​ – curiousguy

ответ

2

Этот макет не реализуется на C++, даже с дополнительным классом помощи.

Тот факт, что этот B наследуется от A, и вы хотите разделить наследование A с C на одной стороне и с D на другом, требует, чтобы B, C и D фактически наследовались от A. Но тогда A будет разделенных по обоим ветвям вашего алмаза.

Альтернативы

Какие альтернативы могут быть?

  • Если бы удалось сломать обмен А между левой и правой ветвей ваших алмазов, вы бы также сломать обмен общей базы.

  • Если бы ввести некоторые промежуточные классы А1, А2 для реализации левой и правой доли в своих отраслях, вы бы, но застрял на то, что оба B должны наследовать либо один, либо другой

  • единственный выход мог бы иметь дубликат класс для В.

Это последнее решение не выполнить ваше требование, но будет выглядеть следующим образом:

struct Base { int x; }; 
struct A : public virtual Base { int a; }; 
struct AC : public A{}; // synonym 
struct B : public virtual A { int b; }; 
struct BC : public virtual AC { int b; }; // !! clone !! 
struct C : public virtual AC { int c; }; 
struct D : public virtual A { int d; }; 
struct E : public BC, C { int e; }; 
struct F : public B, D { int f; }; 
struct Final : public E, F { }; 

А вот доступ к ЧЛЕНАМ:

Final f; 
f.x = 2; // unambiguous: there's onely one of it 
f.f = 1; 
f.e = 2; 
f.d = 3; 
f.c = 4; 
//f.b = 5; // ambiguous: there are two of it 
f.E::b = 5; // successful desambiguation 
f.F::b = 6; // successfuldesambiguation 
//f.a = 7; // ambiguous: there are two of it 
f.E::a = 7; // successful desambiguation 
f.F::a = 8; // successful desambiguation 

Чтобы вернуться к вашей постановке задачи: вы говорите, что не можете вмешиваться выше E и F.В этом случае ваши варианты очень ограничены:

  • вы публично наследовать
  • вы в частном порядке наследования через несколько промежуточных классов

Но эффект был бы тот же общий доступ к, как и следующий код desmonstrates (на в верхней части приведенной выше):

class FI : private F // make F private 
{ public: 
    void set_xa(int u, int v) { x = u; a= v; } 
    void show_xa() { cout << "x:" << x << " a:" << a << endl; } 
}; 
class EI : private E // make E private 
{ 
public: 
    void set_xa(int u, int v) { x = u; a = v; } 
    void show_xa() { cout << "x:" << x << " a:" << a << endl; } 
}; 

struct Final3 : public EI, public FI { }; 

Final3 h; 
h.EI::set_xa(3, 4); 
h.FI::set_xa(5, 6); 
h.EI::show_xa(); 
h.FI::show_xa(); 
// the shared virtually inherited memebers are still shared ! 

Вывод:

С наследованием вы полностью связаны дизайном выше E и F, на который вам не разрешено влиять.

Так что первые вопросы будут:

  • вы не можете изменить эту конструкцию после всех (т.е. клонирование одного B)?
  • не было бы неприемлемо, если бы между двумя ветвями была A, а может быть, есть веская причина?

Если вы отвечаете не на оба вопроса, вам придется пойти на композиции, а также осуществлять своего рода proxy design pattern, где ваш объект, состоящий является прокси для обоих компонентов.

+0

Если A не является виртуальным, как B и C или B и D имеют один A? –

+0

@JackSabbath - полностью прав, извините: я прочитал вопрос, чтобы быстро и не заметил двух общих B. Я сделал всеобъемлющее редактирование. – Christophe

+0

благодарит вас за подробное объяснение. Я действительно спросил об этом, потому что я являюсь автором библиотеки, поэтому я хотел выяснить, будет ли этот шаблон дизайна тупиком до его реализации. Я думаю, что моя модель может быть реализована, если E физически получен из A, тогда как B и C не будут получены из A, а вместо этого используют любопытный повторяющийся шаблон шаблона для доступа к A, который E унаследован. То же самое для другой стороны диаграммы. Конечно, B не будет иметь тот же тип (специализация CRTP). Им нужен базовый класс интерфейса. Я лучше забуду этот образец. –

Смежные вопросы