Множественное наследование с методами столкновения - PullRequest
3 голосов
/ 05 апреля 2011

Я пишу несколько шаблонных чистых виртуальных базовых классов, которые наследуются многократно и обнаружили незначительную странность в этом процессе.Суть в том, что если вы определяете один и тот же метод в двух базовых классах, наследование от обоих компилируется и работает нормально, и кажется, что вам нужно только одно определение в производном классе.Мне любопытно, что происходит за кулисами здесь, это правильное и запланированное поведение или опасный недосмотр компилятора?

См. Иллюстративный пример кода ниже:

namespace
{
  template <typename T_NumType>
  class InheritFrom
  {
  public:
    virtual void doSomething(const T_NumType& numType) = 0;

    virtual void sharedMethod() = 0;

  }; // class

  class MultipleInheritor : public InheritFrom<int>, public InheritFrom<float>
  {
  public:
    void doSomething(const int& numType) {}
    void doSomething(const float& numType) {}

    void sharedMethod() {} // one definition here

  }; // class

}

int main(int argc, char** argv)
{
  MultipleInheritor mult;
  mult.doSomething(5);
  mult.sharedMethod();

}

РЕДАКТИРОВАТЬ:
Ответы ниже и взгляд на стандарт C ++ 98 наконец-то прояснили это для меня.

Из 10.3: Виртуальные функции:

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

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

Таким образом, в представленном мною случае действительно есть две функции базового класса, и из-за поиска имени члена единственная функция в производном классе определяется как final overrider для обоих.Итак, то, что у меня есть, прекрасно сформировано и является логическим результатом работы компилятора C ++.

Ответы [ 2 ]

2 голосов
/ 05 апреля 2011

Функции имеют разные подписи (одна принимает целое число, а другая - число с плавающей запятой), и поэтому они на самом деле не "одинаковы".

Магия шаблона немного запутывает это, но это то же самое, что если бы у вас были foo(int) и foo(float) - это две разные функции. Вы можете иметь foo(int) const и foo(int), это будут две разные функции.

РЕДАКТИРОВАТЬ: Хорошо, позвольте мне обратиться к фактическому вопросу (как указано в вашем комментарии). Технически это все еще не является двусмысленным: каждая версия InheritFrom имеет свой собственный vtable, а MultipleInheritor имеет один vtable. Вы можете выбрать область действия любой родительской реализации sharedMethod (например, InheritFrom<int>::sharedMethod()), но для вызывающей стороны ваш объект типа MultipleInheritor имеет одну vtable с одной записью для sharedMethod.

РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ: Ключ в том, что вы реализуете sharedMethod в своем подклассе. Если бы он не был чистым и в MultipleInheritor не было реализации, то была бы ошибка компилятора, так как не было бы понятно, что поместить в один слот в vtable.

1 голос
/ 05 апреля 2011

Переопределение двух виртуальных функций с одним и тем же именем в одном определении функции в производном классе - это одна особенность множественного наследования в C ++.

Бьярн Страуструп описал здесь одну возможную реализацию MI с виртуальными функциями: Множественное наследование для C ++

По существу, InheritFrom<int> vtable и InheritFrom<float> vtable MultipleInheritor модифицируются так, что обе записи для sharedMethod указывают на MultipleInheritor::sharedMethod.

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