使用声明作为覆盖
Using declaration as overrider
我们在标准中有以下简单(并略微修改以添加 main
和输出)示例:
struct A {
virtual void f()
{
cout << "A\n";
}
};
struct B : virtual A {
virtual void f()
{
cout << "B\n";
}
};
struct C : B, virtual A {
using A::f;
};
int main()
{
C c;
c.f(); // calls B::f, the final overrider
c.C::f();
return 0;
}
从中我们可以得出结论,using A::f
不存在覆盖。但是标准中的什么措辞规定了它?以下是 C++17 草案 ([class.virtual]p2) 中最终覆盖程序的措辞:
<...> A virtual member function C::vf of a class object S is a final
overrider unless the most derived class (4.5) of which S is a base
class subobject (if any) declares or inherits another member
function that overrides vf. In a derived class, if a virtual member
function of a base class subobject has more than one final overrider
the program is ill-formed.
而且我无法找到 "overrides" 的真正含义。如果它未定义并且我们将任何声明视为覆盖程序,那么我们应该将 using 声明视为覆盖程序,因为 [namespace.udecl]p2 说:
Every using-declaration is a declaration and a member-declaration and can therefore be used in a class definition.
我理解标准使用声明不引入覆盖程序的意图,但是有人可以指出我在标准语中的实际引用吗?这是第一部分,现在是第二部分
考虑以下代码:
#include <iostream>
#include <string>
using std::cout;
class A {
public:
virtual void print() const {
cout << "from A" << std::endl;
}
};
class B: public A {
public:
void print() const override {
cout << "from B" << std::endl;
}
};
class C: public A {
public:
void print() const override {
cout << "from C" << std::endl;
}
};
class D: public B, public C {
public:
using C::print;
};
int main()
{
D d{};
d.print();
return 0;
}
如果 using 声明没有引入覆盖器,那么我们在 D
中有 2 个最终覆盖器,因此 - 由于
的未定义行为
In a derived class, if a virtual member
function of a base class subobject has more than one final overrider
the program is ill-formed.
对吗?
using 声明,虽然就声明区域而言确实是声明,但不是 函数声明。我们可以看到它在语法上是指定的:
[dcl.dcl]
1 Declarations generally specify how names are to be interpreted.
Declarations have the form
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 ;
并且在某种程度上是语义上的。由于以下段落详细说明了从基 class 引入成员函数的 using 声明与派生 class.
中的成员函数声明有何不同
[namespace.udecl]
15 When a using-declarator brings declarations from a base class
into a derived class, member functions and member function templates
in the derived class override and/or hide member functions and member
function templates with the same name, parameter-type-list,
cv-qualification, and ref-qualifier (if any) in a base class (rather
than conflicting). Such hidden or overridden declarations are excluded
from the set of declarations introduced by the using-declarator.
16 For the purpose of overload resolution, the functions that are
introduced by a using-declaration into a derived class are treated as
though they were members of the derived class. In particular, the
implicit this parameter shall be treated as if it were a pointer to
the derived class rather than to the base class. This has no effect on
the type of the function, and in all other respects the function
remains a member of the base class.
考虑到这一点,如果考虑到您引用的第一段的开头:
[class.virtual]
2 If a virtual member function vf
is declared in a class Base
and in a class Derived, derived directly or indirectly from Base, a
member function vf with the same name, parameter-type-list,
cv-qualification, and ref-qualifier (or absence of same) as
Base::vf
is declared, then Derived::vf
is also virtual
(whether or not it is so declared) and it overrides Base::vf
. For
convenience we say that any virtual function overrides itself.
我们可以看到它是一个虚函数声明,它可以在基class中为虚函数引入覆盖。由于 using 声明不是函数声明,因此它不合格。
当前的措辞部分来自CWG Defect 608。它旨在澄清该报告中有问题的解释,并将使用声明与虚函数覆盖的概念分离。
关于你的第二个问题,引述中需要注意的重要一点是 "of a base class subobject"。您的代码示例在 D
中有 two A
个子对象(该示例中的继承不是虚拟的)。每个人都有自己的最终覆盖,分别在 B
和 C
中。因此该程序不是病式的,无论是否在 D
.
中声明了另一个覆盖程序
您关注的段落适用于虚拟继承的情况。如果 B
和 C
有一个虚拟的 A
基础,并且 D
从两者继承而不覆盖 print
,程序 would be ill-formed。由于上述原因,像 using C::print
这样的 using 声明不会使其格式正确。
我们在标准中有以下简单(并略微修改以添加 main
和输出)示例:
struct A {
virtual void f()
{
cout << "A\n";
}
};
struct B : virtual A {
virtual void f()
{
cout << "B\n";
}
};
struct C : B, virtual A {
using A::f;
};
int main()
{
C c;
c.f(); // calls B::f, the final overrider
c.C::f();
return 0;
}
从中我们可以得出结论,using A::f
不存在覆盖。但是标准中的什么措辞规定了它?以下是 C++17 草案 ([class.virtual]p2) 中最终覆盖程序的措辞:
<...> A virtual member function C::vf of a class object S is a final overrider unless the most derived class (4.5) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.
而且我无法找到 "overrides" 的真正含义。如果它未定义并且我们将任何声明视为覆盖程序,那么我们应该将 using 声明视为覆盖程序,因为 [namespace.udecl]p2 说:
Every using-declaration is a declaration and a member-declaration and can therefore be used in a class definition.
我理解标准使用声明不引入覆盖程序的意图,但是有人可以指出我在标准语中的实际引用吗?这是第一部分,现在是第二部分
考虑以下代码:
#include <iostream>
#include <string>
using std::cout;
class A {
public:
virtual void print() const {
cout << "from A" << std::endl;
}
};
class B: public A {
public:
void print() const override {
cout << "from B" << std::endl;
}
};
class C: public A {
public:
void print() const override {
cout << "from C" << std::endl;
}
};
class D: public B, public C {
public:
using C::print;
};
int main()
{
D d{};
d.print();
return 0;
}
如果 using 声明没有引入覆盖器,那么我们在 D
中有 2 个最终覆盖器,因此 - 由于
In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.
对吗?
using 声明,虽然就声明区域而言确实是声明,但不是 函数声明。我们可以看到它在语法上是指定的:
[dcl.dcl]
1 Declarations generally specify how names are to be interpreted. Declarations have the form
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 ;
并且在某种程度上是语义上的。由于以下段落详细说明了从基 class 引入成员函数的 using 声明与派生 class.
中的成员函数声明有何不同[namespace.udecl]
15 When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declarator.
16 For the purpose of overload resolution, the functions that are introduced by a using-declaration into a derived class are treated as though they were members of the derived class. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of the base class.
考虑到这一点,如果考虑到您引用的第一段的开头:
[class.virtual]
2 If a virtual member function
vf
is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) asBase::vf
is declared, thenDerived::vf
is also virtual (whether or not it is so declared) and it overridesBase::vf
. For convenience we say that any virtual function overrides itself.
我们可以看到它是一个虚函数声明,它可以在基class中为虚函数引入覆盖。由于 using 声明不是函数声明,因此它不合格。
当前的措辞部分来自CWG Defect 608。它旨在澄清该报告中有问题的解释,并将使用声明与虚函数覆盖的概念分离。
关于你的第二个问题,引述中需要注意的重要一点是 "of a base class subobject"。您的代码示例在 D
中有 two A
个子对象(该示例中的继承不是虚拟的)。每个人都有自己的最终覆盖,分别在 B
和 C
中。因此该程序不是病式的,无论是否在 D
.
您关注的段落适用于虚拟继承的情况。如果 B
和 C
有一个虚拟的 A
基础,并且 D
从两者继承而不覆盖 print
,程序 would be ill-formed。由于上述原因,像 using C::print
这样的 using 声明不会使其格式正确。