Множественный полиморфизм в C ++ - PullRequest
2 голосов
/ 01 февраля 2012

Существует ошибка компиляции "'A' является неоднозначной базой 'C'", существующей в тесте diamond multiple inheritance ниже,

struct A { void f();};
struct B1: A {};
struct B2: A {};
struct C: B1, B2 {};

void g() {A *o = new C;}

Она решается с помощью virtual inheritance ниже,

struct B1: virtual A {};
struct B2: virtual A {};

Теперь есть ошибка компиляции "нет уникального окончательного переопределения для 'virtual void A :: f ()' в 'C'", существующего в другом тесте diamond multiple polymorphism ниже,

struct A {virtual void f();};
struct B1: virtual A {void f();};
struct B2: virtual A {void f();};
struct C: B1, B2 {};

void g() {
 A *o = new C;
 o->f();
}

Иона не может быть решена даже с помощью dynamic_cast ниже,

dynamic_cast<B1 *>(o)->f();

@ NOTE

dynamic_cast<T *>(obj_ptr) фактически используется для выполнения typesafe downcast, то есть когдатип времени выполнения Tobj объекта, на который указывает obj_ptr, является подтипом T, он возвращает сам obj_ptr;в противном случае указатель NULL.Ошибочно думать, что преобразование подтипа Tobj в супертип T приводит к обратному выводу, иначе выполнение upcast во время выполнения прямо противоречит принципу полиморфизма.

IMHO, virtual inheritance достаточно кратко для решения проблемы первой половиныво время компиляции.Напротив, можете ли вы представить что-нибудь, чтобы решить проблему второй половины во время выполнения?

@ EDIT

Спасибо за ваше указание dynamic_cast несделать работу.Исправлено.

Чтобы решить проблему 2-й половины, кажется, что у него нет выбора, кроме как реализовать переопределение в последнем подклассе иерархии алмазов ниже,

struct C: B1, B2 {
 void f() {B1::f();} //Hardcode to your choice of overrider
};

Ответы [ 4 ]

2 голосов
/ 01 февраля 2012

Ну, у вас все еще нет уникального переопределения для f(): это нужно определить в C, например, например ::100100 *

struct C: B1, B2 { void f() { this->B1::f(); } };

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

2 голосов
/ 01 февраля 2012

Ваш второй пример плохо сформирован, даже без звонка. Компилятор, который принимает его, не соответствует стандарту. Это хорошо иллюстрируется стандартом C ++ (C ++ 11 / 10.3.13):

В следующем примере показана функция, которая не имеет уникального окончательное переопределение:

struct A { 
  virtual void f(); 
}; 

struct VB1 : virtual A { // note virtual derivation 
  void f(); 
}; 

struct VB2 : virtual A {
  void f(); 
}; 

struct Error : VB1, VB2 { // ill-formed }; 

struct Okay : VB1, VB2 { 
  void f(); 
}; 

И VB1 :: f, и VB2 :: f переопределяют A :: f, но есть не переопределяет их обоих в классе Error. Этот пример поэтому плохо сформирован. Класс Хорошо, однако, хорошо сформирован, потому что Okay :: f - окончательное переопределение.

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

struct Okay : VB1, VB2 { 
  void f() { 
    VB1::f(); 
    VB2::f(); 
  }
}; 
0 голосов
/ 01 февраля 2012

Возможно, вам также нужно виртуально количественно определить f () в подклассах.

struct A {virtual void f();};
struct B1: virtual A {virtual void f();};
struct B2: virtual A {virtual void f();};
struct C: B1, B2 {};

void g() {
 A *o = new C;
 o->f();
}
0 голосов
/ 01 февраля 2012

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

...