Подтвердить что ты не робот

Переопределить виртуальную функцию базовых классов, которые не имеют общего интерфейса

#include <iostream>
struct B1
{
    virtual void method()=0;
    virtual ~B1(){}
};

struct B2
{
    virtual void method()=0;
    virtual ~B2(){}
};

struct D: B1, B2
{
    virtual void method()
    {
        std::cout << "D::method\n";
    };
};

int main(int argc,char *argv[])
{
    D d;
    B1 &b1=d;
    B2 &b2=d;
    b1.method();
    b2.method();
    return 0;
}

Примечание. B1 и B2 не имеют общего интерфейса.

Это законно? Если да - в каком стандарте? С++ 98/03/11?

Оба, msvc и gcc скомпилировали его в порядке.

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

Имеет ли такая ситуация какое-то особое имя?

Как это работает в деталях, пожалуйста? Может быть, некоторые ссылки ISO?

4b9b3361

Ответ 1

Ваш код хорошо сформирован: void D::method() отменяет как void B1::method(), так и void B2::method().

В спецификации указано (С++ 11 §10.3/2):

Если виртуальная функция-член vf объявлена ​​в классе Base и в классе Derived, полученном прямо или косвенно из Base, функция-член vf с тем же именем, тип параметра -list, cv-qualification и ref-qualifier (или отсутствие того же), что и Base::vf, тогда Derived::vf также является виртуальным (независимо от того, объявлен он или нет), и он переопределяет Base::vf.

B1 объявляет виртуальную функцию-член void B1::method(). Класс D выводится из B1, а также объявляет функцию-член с тем же именем (method), тот же список параметров (без параметров), ту же квалификацию cv (без квалификации) и тот же ref- квалификатор (без квалификации).

Поэтому void D::method() переопределяет void B1::method().

Та же логика применяется для void B2::method() (просто замените B2 на B1 в приведенном выше объяснении), поэтому void D::method() переопределяет как void B1::method(), так и void B2::method().

Ответ 2

afaik это законно в каждом стандарте. Я не уверен, имеет ли он свое собственное имя, но похоже на проблему .

если вы переопределите "виртуальный метод void()" в D, вы переопределите оба метода в B1 и B2.

Edit:

чтобы ответить, почему у вас нет "двух разных автономных унаследованных виртуальных функций в D: B1:: method и B2:: method":

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

Представьте, что это было бы возможно, тогда он мог бы выглядеть примерно так:

struct D: B1, B2
{
    virtual void B1::method()
    {
        std::cout << "D::method\n";
    };
    virtual void B2::method()
    {
        std::cout << "D::method\n";
    };
};

, но, увидев это, вы уже можете сказать, что нет возможности иметь что-то подобное, потому что при вызове

objectD.method()

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

EDIT: "не может указать, какой из них вы вызываете". ссылается, вы не можете указать, хотите ли вы вызвать перегрузку класса D метода B2:: или самого метода B2. Метод objectD.B2:: всегда будет вызывать метод B2 (не перегруженный) (который в этом случае не будет компилироваться, поскольку B2 не имеет реализации)