#c #language-lawyer
#c #язык-юрист
Вопрос:
Я придумал следующий код, определяющий во время компиляции, переопределены ли унаследованные функции в производном классе. Он работает со всеми основными компиляторами — gcc / clang / msvc. Но действительно ли этот подход поддерживается стандартом?
#include <type_traits>
struct B {
virtual void f1() {}
virtual void f2() {}
void f3() {}
void f4() {}
};
struct D: B {
void f1() override {}
void f3() {}
};
int main()
{
static_assert(!std::is_same_v<decltype(amp;B::f1), decltype(amp;D::f1)>, "overriden");
static_assert(std::is_same_v<decltype(amp;B::f2), decltype(amp;D::f2)>, "base");
static_assert(!std::is_same_v<decltype(amp;B::f3), decltype(amp;D::f3)>, "overriden");
static_assert(std::is_same_v<decltype(amp;B::f4), decltype(amp;D::f4)>, "base");
return 0;
}
Комментарии:
1. Мне это кажется странным, интуитивно типы
void(B::*)()
иvoid(D::*)()
должны отличаться независимо от того, перегружена функция или нет. Но я не языковой юрист…2.Как это работает с частным наследованием? И
D::f3
точнее сказать, скрыватьB::f3()
, а не переопределять.B::f3
в этом примере никогда не следует считать переопределенным вvirtual
смысле. Вы хотите отличить переопределенныеvirtual
функции от нефункциональныхvirtual
?3. Наследование по умолчанию для
struct
общедоступно.
Ответ №1:
Найдено, это описано в разделе by 20.15.9 Member relationships
, пункт 5 стандарта:
Примечание: Тип выражения указателя на член
amp;C::b
не всегда является указателем на членC
, что приводит к потенциально неожиданным результатам при использовании этих функций в сочетании с наследованием.
Приведенный пример:
struct A { int a; };
struct B { int b; };
struct C: public A, public B { };
// The following will succeed because, despite its appearance,
// amp;C::b has type "pointer to member of B of type int"
static_assert(is_pointer_interconvertible_with_class( amp;C::b ));
И так далее и тому подобное. Это объясняет, почему в вашем примере, amp;B::f2
а amp;D::f2
также amp;B::f4
и amp;D::f4
имеют один и тот же тип void(B::*)()
.
Комментарии:
1. Не могли бы вы привести и подчеркнуть соответствующие отрывки? Завершающий комментарий немного сложен для чтения. И какое это имеет отношение к
virtual
функциям или функциям-членам вообще?2. Хороший ответ, хорошо найден @Peter. Надеюсь, вы не возражаете против редактирования.
3. @alterigel: тот факт, что указатель на члены, с которыми мы здесь имеем дело, является указателем на виртуальные функции, не имеет отношения к тому, почему это работает, имеет значение только то, что указатель на член для унаследованного (не переопределенного и не скрытого) члена имеет тип указатель на член базового класса типа …