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

Visual Studio 2013.

Дано:

class base_1
{
public:
virtual void foo(int) = 0;
};

class base_2
{
public:
virtual void foo(int, double) = 0;
};

class join_1_2 : public virtual base_1, public virtual base_2
{};

У меня есть раковина:

void sink(join_1_2 &param)
{
param.foo(42, 3.14);
}

Но я получаю следующие ошибки компилятора:

ошибка C2385: неоднозначный доступ к ‘foo’

может быть ‘foo’ в базе ‘base_1’

или может быть ‘foo’ в базе ‘base_2’

ошибка C2660: «base_1 :: foo»: функция не принимает 2 аргумента

ошибка C3861: ‘foo’: идентификатор не найден

Я знаю, что могу решить эту проблему с помощью:

param.base_2::foo(42, 3.14);

Но, как вы можете себе представить, виртуальное наследование — это уже один грех, с которым мне приходится жить. Я, вероятно, собираюсь написать адаптер. Но я не понимаю, что мешает компилятору решить foo в base_2. Мой коллега считает, что это ошибка компилятора, но я не так быстро винить вендора.

Что спецификация C ++ говорит о разрешении перегруженных виртуальных методов в базовых классах?

4

Решение

Это действительно двусмысленность в соответствии со стандартом, но вы можете использовать using или укажите базовый класс явно:

class join_1_2 : public virtual base_1, public virtual base_2
{
public:
using base_1::foo;
using base_2::foo;
};

void sink(join_1_2 &param)
{
param.base_2::foo(42, 3.14);
}

7.3.3 Объявление об использовании

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

4

Другие решения

Эмпирическое правило заключается в том, что функции в разных областях не перегружаются — здесь наши fooС в разных сферах. Если вы хотите, чтобы они перегрузились, вы захотите ввести их с используя декларирование:

class join_1_2 : public virtual base_1, public virtual base_2
{
public:
using base_1::foo;
using base_2::foo;
};
4