Почему чисто виртуальный механизм не учитывает унаследованные функции? - PullRequest
2 голосов
/ 11 апреля 2011

Прежде чем спросить, я имел в виду этот старый вопрос . Но у меня все еще есть вопросы.

struct B1 {
  virtual void fun () = 0;
};
struct B2 {
  void fun () { cout<<"B2::fun()\n"; }
  void fun (int i) {}
};
struct D : B1, B2 {
  using B2::fun;  // This line doesn't help
};

int main ()
{
  B1 *pB1 = new D;  // Error: cannot allocate 'D' because 'B1::fun()' is abstract
  pB1->fun();
}
  1. Любая причина, по которой стандарт C ++ не принимает унаследованные функции-члены для разрешения механизма pure virtual?
  2. Почему ключевое слово using не помогает устранить эту ошибку? (компилятор: linux-64 g ++)
  3. Какая функция используется для ключевого слова using, B2::fun() или B2::fun(int)? (для этой строки нет двусмысленности)

Ответы [ 5 ]

2 голосов
/ 11 апреля 2011
using B2::fun;

Просто позволяет использовать метод B2::fun, но поскольку B1 является абстрактным классом, вы должны реализовать чисто виртуальную функцию fun этого класса, чтобы иметь возможность создать свои объекты.

0 голосов
/ 11 апреля 2011

Какая функция используется для использования ключевого слова, B2 :: fun () или B2 :: fun (int)?(для этой строки не существует двусмысленности)

Из ИСО / МЭК 14882: 2003 (E) 7.3.3.12

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

[Example:
    struct B { 
        virtual void f(int);
        virtual void f(char); 
        void g(int); 
        void h(int);
    };

    struct D : B { 
        using B::f;
        void f(int);   // OK: D::f(int) overrides B::f(int);

        using B::g; 
        void g(char);  // OK

        using B::h; 
        void h(int);   // OK: D::h(int) hides B::h(int)
    };

    void k(D* p) {
        p->f(1);    //calls  D::f(int)
        p->f(’a’);  //calls  B::f(char)  // Notice the call being resolved
        p->g(1);    //calls  B::g(int)
        p->g(’a’);  //calls  D::g(char)
    }

— end example] 

[Примечание: два объявления-использования могут вводить функции с одинаковыми именами и одинаковыми типами параметров.Если для вызова неквалифицированного имени функции разрешение перегрузки функции выбирает функции, представленные такими объявлениями использования, то вызов функции некорректен.]

Итак, в приведенном вами примере нет никакой двусмысленности.В зависимости от переданного параметра, вызов метода может быть решен.

0 голосов
/ 11 апреля 2011

Я ни в коем случае не эксперт по C ++, но позвольте мне попробовать:

  1. Я думаю, что B1 и B2, с точки зрения компилятора, - это два совершенно разных класса, в каждом из которых есть метод с одинаковым именем. Даже когда речь идет о сфере действия D, у компилятора нет причин использовать реализацию fun () B2 для реализации fun () из B1. (Полагаю, мы могли бы получить что-то ясное, если взглянем на механизм виртуальных таблиц. Там мы можем увидеть, почему B2 :: fun () не помогает B1 в fun ().)

  2. Директива «using» просто делает символ «забавным» видимым в области видимости D. «Использование» не добавляет никакой реализации fun () к классу D (но D нуждается в реализации для B1 :: fun ()).

  3. Хмм ... Директива «здесь» на самом деле не «использует» (или мы говорим «вызвать») ни то, ни другое. «использование» просто вводит имена в область видимости D (AKA делает имена видимыми в области видимости D, аналогично объявлению их снова).

0 голосов
/ 11 апреля 2011

using только корректирует процесс поиска имени. Он не импортирует функцию в заданную область и не определяет новую функцию.

Итак, вам просто нужно определить новое virtual переопределение.

0 голосов
/ 11 апреля 2011

Хорошо. Я получил ответ для 1-го только на основе логических рассуждений, хотя. Предположим, стандарт принимал унаследованные методы для разрешения механизма pure virtual, тогда для обычных «виртуальных» функций будет неоднозначность.

т.е. Предположим, что B1::fun() - это обычная виртуальная функция, тогда будет путаница в выборе между B1::fun() и B2::fun(). Так что лучше избегать рассмотрения унаследованных членов хотя бы для механизма virtual.

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