Объявление использования, хотя действительно объявление в отношении декларативных областей, не является объявлением функции . Мы можем видеть это указано грамматически:
[dcl.dcl]
1 Объявления обычно определяют, как имена должны интерпретироваться.
Объявления имеют вид
declaration:
block-declaration
nodeclspec-function-declaration
function-definition
template-declaration
deduction-guide
explicit-instantiation
explicit-specialization
linkage-specification
namespace-definition
empty-declaration
attribute-declaration
block-declaration:
simple-declaration
asm-definition
namespace-alias-definition
using-declaration
using-directive
static_assert-declaration
alias-declaration
opaque-enum-declaration
nodeclspec-function-declaration:
attribute-specifier-seq declarator ;
И в некоторой степени семантически. Поскольку в следующих параграфах подробно описано, как объявление using, представляющее функции-члены из базового класса, отличается от объявлений функций-членов в производном классе.
[namespace.udecl]
15 Когда использование-декларатор приносит объявления из базового класса
в производный класс, функции-члены и шаблоны функций-членов
в производном классе переопределяют и / или скрывают функции-члены
шаблоны функций с тем же именем, параметр-тип-список,
cv-квалификация и ref-квалификатор (если есть) в базовом классе (скорее
чем противоречивый). Такие скрытые или переопределенные объявления исключаются
из набора объявлений, введенных оператором using.
16 Для разрешения перегрузки функции, которые
введенные объявлением использования в производный класс рассматриваются как
хотя они были членами производного класса. В частности,
неявный этот параметр должен рассматриваться как указатель на
производный класс, а не базовый класс. Это не влияет на
тип функции и во всех других отношениях функция
остается членом базового класса.
Имея это в виду, если принять во внимание начало первого абзаца, вы цитируете:
[class.virtual]
2 Если функция виртуального члена vf
объявлена в классе Base
и в классе Derived, полученном прямо или косвенно из Base,
функция-член vf с тем же именем, параметр-тип-список,
cv-квалификация и ref-квалификатор (или его отсутствие) как
Base::vf
объявлено, тогда Derived::vf
также является виртуальным
(независимо от того, объявлено оно или нет), и оно переопределяет Base::vf
. За
Для удобства мы говорим, что любая виртуальная функция переопределяет себя.
Мы можем видеть, что это виртуальное объявление функции , которое может ввести переопределение для виртуальной функции в базовом классе. А поскольку объявление using не является объявлением функции, оно не подходит.
Нынешняя формулировка частично относится к CWG Defect 608 . Он призван прояснить проблемную интерпретацию в этом отчете и отделить использование объявлений от понятия переопределения виртуальных функций.
Что касается вашего второго вопроса, важно отметить в этой цитате "базового класса подобъекта " . В вашем примере кода есть два A
подобъекта в D
(наследование в этом примере не виртуальное). И у каждого есть свой окончательный переопределение в B
и C
соответственно. Таким образом, программа не является некорректной, с или без переопределения, объявленного в D
.
Пункт, который вас интересует, относится к случаю виртуального наследования. Если бы B
и C
имели виртуальную базу A
, а D
унаследовали от обоих без переопределения print
, программа была бы плохо сформирована . А объявление об использовании, такое как using C::print
, не будет правильно сформировано, опять же по причинам, указанным выше.