"hidden overloaded virtual function" 超过 2 类
"hidden overloaded virtual function" with more than 2 classes
最小示例:
class A {};
class B : public virtual A {};
class C : public virtual B {};
// define two overloading virtual functions
// no inheritance, so no overriding/hiding in this class
struct visitor1
{
virtual void visit(A& ) {}
virtual void visit(B& ) {}
virtual ~visitor1();
};
// covariant types are not allowed for overriding virtuals,
// so the C-visit function would hide A and B, so we add them
// using the "using" keyword
struct visitor2 : public visitor1
{
using visitor1::visit;
virtual void visit(C& ) {}
virtual ~visitor2();
};
// the B-visit is a correct override
// without the use of "using" (or the C-visit) below, the
// compiler warns that the C-visit function from visitor3
// is being overridden
struct visitor3 final : public visitor2
{
//using visitor2::visit;
//void visit(C &) override {}
void visit(B &) override {}
};
编译器:
$ clang++ -Wall -Wextra -Weverything -Wno-c++98-compat visitor.cpp
visitor.cpp:32:14: warning: 'visitor3::visit' hides overloaded virtual function [-Woverloaded-virtual]
void visit(B &) override {}
^
visitor.cpp:20:22: note: hidden overloaded virtual function 'visitor2::visit' declared here: type mismatch at 1st parameter ('C &' vs 'B &')
virtual void visit(C& ) {}
^
问题(假设 visitor3 的评论行保持评论状态):
- 为什么编译器抱怨
visitor3::visit(B&)
隐藏了 visitor2::visit(C&)
?
- 为什么不抱怨
visitor3::visit(B&)
隐藏visitor1::visit(A&)
(这里有什么不同)?
附加问题:如何实现 visitor2::visit(C&)
和 visitor1::visit(A&)
都不隐藏在 visitor3
中? visitor3
中的 using visitor2::visit;
是否足够?
void visit(B&)
的声明或任何名为 visit
的成员(它可能是数据成员 int visit;
)在 visitor3
中的声明隐藏了父类的任何成员称为 visit
.
这里编译器的warning更是个好东西。它识别出一个常见的错误模式,即在不考虑重载的情况下重写基本虚拟成员函数。但它不会检测所有隐藏名称,或者不会对所有隐藏名称发出警告。无论如何,visitor1
和 visitor2
中的所有 visit
都被隐藏了。
附加答案:命名基class成员的using声明是基中所有成员的派生class中的声明class 具有该名称且可见。因此,这有效地包括了在基 class 中也由 using 声明声明的成员。
(这些由 using 声明声明的成员表现得非常接近,就好像它们是在 class 中首次声明的实际成员一样。即使重载决策也认为它们的隐含对象参数是派生的 class.)
"Hiding" 是 shorthand 的真实情况。规则很简单 ():查找名称时,编译器从当前作用域开始;如果它找到那个名字,它就完成了。如果找不到它,它会移动到下一个封闭范围。重复直到完成。
将其与重载发生的规则相结合仅在同一作用域定义的函数中。一旦编译器找到该名称,同一范围内的所有定义都会参与重载。编译器不会在外部作用域中查找可能与名称匹配的内容。那就是疯狂。
请注意,姓名查找仅查找姓名;它不依赖于找到的名称是否覆盖基 class 中的名称,也不依赖于当前作用域中是否存在多个具有相同名称的函数(即名称被重载)。找到名称后,搜索结束。该范围中该名称的所有定义都参与重载。
因此,visitor3
中的 void visit(B&)
隐藏了 所有基 class 中 visit
的所有其他定义 es。该名称在 visitor3
中定义,因此编译器不会在其他任何地方查找。
最小示例:
class A {};
class B : public virtual A {};
class C : public virtual B {};
// define two overloading virtual functions
// no inheritance, so no overriding/hiding in this class
struct visitor1
{
virtual void visit(A& ) {}
virtual void visit(B& ) {}
virtual ~visitor1();
};
// covariant types are not allowed for overriding virtuals,
// so the C-visit function would hide A and B, so we add them
// using the "using" keyword
struct visitor2 : public visitor1
{
using visitor1::visit;
virtual void visit(C& ) {}
virtual ~visitor2();
};
// the B-visit is a correct override
// without the use of "using" (or the C-visit) below, the
// compiler warns that the C-visit function from visitor3
// is being overridden
struct visitor3 final : public visitor2
{
//using visitor2::visit;
//void visit(C &) override {}
void visit(B &) override {}
};
编译器:
$ clang++ -Wall -Wextra -Weverything -Wno-c++98-compat visitor.cpp
visitor.cpp:32:14: warning: 'visitor3::visit' hides overloaded virtual function [-Woverloaded-virtual]
void visit(B &) override {}
^
visitor.cpp:20:22: note: hidden overloaded virtual function 'visitor2::visit' declared here: type mismatch at 1st parameter ('C &' vs 'B &')
virtual void visit(C& ) {}
^
问题(假设 visitor3 的评论行保持评论状态):
- 为什么编译器抱怨
visitor3::visit(B&)
隐藏了visitor2::visit(C&)
? - 为什么不抱怨
visitor3::visit(B&)
隐藏visitor1::visit(A&)
(这里有什么不同)?
附加问题:如何实现 visitor2::visit(C&)
和 visitor1::visit(A&)
都不隐藏在 visitor3
中? visitor3
中的 using visitor2::visit;
是否足够?
void visit(B&)
的声明或任何名为 visit
的成员(它可能是数据成员 int visit;
)在 visitor3
中的声明隐藏了父类的任何成员称为 visit
.
这里编译器的warning更是个好东西。它识别出一个常见的错误模式,即在不考虑重载的情况下重写基本虚拟成员函数。但它不会检测所有隐藏名称,或者不会对所有隐藏名称发出警告。无论如何,visitor1
和 visitor2
中的所有 visit
都被隐藏了。
附加答案:命名基class成员的using声明是基中所有成员的派生class中的声明class 具有该名称且可见。因此,这有效地包括了在基 class 中也由 using 声明声明的成员。
(这些由 using 声明声明的成员表现得非常接近,就好像它们是在 class 中首次声明的实际成员一样。即使重载决策也认为它们的隐含对象参数是派生的 class.)
"Hiding" 是 shorthand 的真实情况。规则很简单 (
将其与重载发生的规则相结合仅在同一作用域定义的函数中。一旦编译器找到该名称,同一范围内的所有定义都会参与重载。编译器不会在外部作用域中查找可能与名称匹配的内容。那就是疯狂。
请注意,姓名查找仅查找姓名;它不依赖于找到的名称是否覆盖基 class 中的名称,也不依赖于当前作用域中是否存在多个具有相同名称的函数(即名称被重载)。找到名称后,搜索结束。该范围中该名称的所有定义都参与重载。
因此,visitor3
中的 void visit(B&)
隐藏了 所有基 class 中 visit
的所有其他定义 es。该名称在 visitor3
中定义,因此编译器不会在其他任何地方查找。