Устранение перегрузок виртуальных методов между базовыми классами
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 ¶m)
{
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++ говорит о разрешении перегруженных виртуальных методов в базовых классах?
2 ответа
Это действительно двусмысленность в соответствии со стандартом, но вы можете использовать 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 ¶m)
{
param.base_2::foo(42, 3.14);
}
7.3.3 Объявление об использовании
В целях разрешения перегрузки функции, которые вводятся посредством объявления об использовании в производный класс, будут обрабатываться так, как если бы они были членами производного класса.
Эмпирическое правило заключается в том, что функции в разных областях не перегружаются - здесь наши foo
S находятся в разных сферах. Если вы хотите, чтобы они были перегружены, вы захотите ввести их с помощью декларации использования:
class join_1_2 : public virtual base_1, public virtual base_2
{
public:
using base_1::foo;
using base_2::foo;
};