Приватная функция перекрывает публичный интерфейс базового класса
Пример:
Подписчик:
class Subscriber {};
Базовый класс:
class SubscribableChannel
{
public:
virtual ~SubscribableChannel() = default;
public:
auto subscribe(Subscriber&) -> void;
auto unsubscribe(Subscriber&) -> void;
private:
virtual auto internal_subscribe(Subscriber&) -> void = 0;
virtual auto internal_unsubscribe(Subscriber&) -> void = 0;
};
auto SubscribableChannel::subscribe(Subscriber& s) -> void
{ internal_subscribe(s); }
auto SubscribableChannel::unsubscribe(Subscriber& s) -> void
{ internal_unsubscribe(s); }
Класс-наследник SubscribableChannel:
class PubSubChannel : public SubscribableChannel
{
public:
PubSubChannel() = default;
private:
auto internal_subscribe(Subscriber&) -> void override {};
auto internal_unsubscribe(Subscriber&) -> void override {};
// Здесь появляется функция `unsubscribe`
// имя которой совпадает с именем одной из функций базового класса,
// но их сигнатуры отличаются: Subscriber& vs (Subscriber&, int)
auto unsubscribe(Subscriber&, int) -> void {}
};
В результате попытка вызова функции unsubscribe:
PubSubChannel channel;
Subscriber s;
channel.unsubscribe(s);
, приводит к следующей ошибке:
error: no matching function for call to ‘PubSubChannel::unsubscribe(Subscriber&)’
note: candidate: ‘void PubSubChannel::unsubscribe(Subscriber&, int)’
Вопрос: является ли данное поведение допустимым? Если да - дайте, пожалуйста, линк на номер параграфа из стандарта C++.
ENV: linux, clang-10/gcc-10
Ответы (1 шт):
Это описывается в
11.8 Member name lookup [class.member.lookup]
2 The following steps define the result of name lookup for a member name f in a class scope C.
3 The lookup set for f in C , called S ( f,C ), consists of two component sets: the declaration set, a set of members named f ; and the subobject set, a set of subobjects where declarations of these members (possibly including using-declarations) were found. In the declaration set, using-declarations are replaced by the set of designated members that are not hidden or overridden by members of the derived class (9.9), and type declarations (including injected-class-names) are replaced by the types they designate. S(f,C) is calculated as follows:
4 If C contains a declaration of the name f , the declaration set contains every declaration of f declared in C that satisfies the requirements of the language construct in which the lookup occurs.
[Note: Looking up a name in an elaborated-type-specifier (6.5.4) or base-specifier (11.7), for instance, ignores all non-type declarations, while looking up a name in a nested-name-specifier (6.5.3) ignores function, variable, and enumerator declarations. As another example, looking up a name in a using-declaration (9.9) includes the declaration of a class or enumeration that would ordinarily be hidden by another declaration of that name in the same scope. —end note]
If the resulting declaration set is not empty, the subobject set contains C itself, and calculation is complete.
5 Otherwise (i.e., C does not contain a declaration of f or the resulting declaration set is empty), S ( f,C ) is initially empty. If C has base classes, calculate the lookup set for f in each direct base class subobject B i , and merge each such lookup set S(f,B i ) in turn into S(f,C).
Так как в PubSubChannel есть объявление unsubscribe, то поиск в базовых классах не производится.