C++ &引用;隐藏重载虚函数“;有两门以上的课程
最简单的例子:C++ &引用;隐藏重载虚函数“;有两门以上的课程,c++,overloading,name-hiding,C++,Overloading,Name Hiding,最简单的例子: 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 v
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& ) {}
^
问题(假设访问者3的评论行保持评论状态):
- 为什么编译器抱怨
正在隐藏visitor3::visit(B&)
visitor2::visit(C&)
- 为什么它不抱怨
正在隐藏visitor3::visit(B&)
(这里有什么不同)visitor1::visit(A&)
附加问题:如何实现
visitor2::visit(C&)
和visitor1::visit(A&)
都不隐藏在visitor3
中?是否使用visitor2::visit执行visitor3
中的code>就足够了?中的无效访问(B&)
声明或名为visit
的成员的任何声明(可能是数据成员int-visit;
)将隐藏名为visit
的父级成员
在这里,编译器的警告更是一件好事。它识别出一种常见的错误模式,即重写基本虚拟成员函数而不考虑重载。但它不会检测所有隐藏的名称,也不会对所有隐藏的名称发出警告。无论如何,来自visitor1
和visitor2
的所有visit
都被隐藏
其他答案:指定基类成员名称的使用声明是基类中所有具有该名称且可见的成员的派生类内的声明。因此,这实际上包括了在基类中通过using声明声明的成员
(这些由using声明声明的成员的行为与第一次在该类中声明的实际成员相似。即使重载解析也会将其隐含的对象参数视为派生类的类型。)“隐藏”是实际情况的简写。规则很简单():当查找名称时,编译器在当前范围内启动;如果它找到了那个名字,它就完蛋了。如果找不到,它将移动到下一个封闭范围。重复,直到完成
将其与只在同一范围内定义的函数之间发生重载的规则相结合。一旦编译器找到该名称,同一作用域中的所有定义都将参与重载。编译器不会在外部作用域中查找可能与名称匹配的内容。那就是疯狂
注意,名称查找只查找名称;它不取决于找到的名称是否覆盖基类中的名称,也不取决于当前作用域中是否有多个同名函数(即名称重载)。找到名称后,搜索结束。该范围内该名称的所有定义都参与重载
因此,visitor3中的voidvisit(B&)
隐藏了visit
在所有基类中的所有其他定义。名称在visitor3
中定义,因此编译器不会查看其他任何地方。如果在visitor2
中声明一个visit(B&)
,会发生什么?@MatthieuBrucher如果您的意思是在visitor2
中声明它,则错误消失。在其他类中,它已经被声明了。voidvisit(B&)
或…的声明隐藏了名为visit“->的父级的任何成员,以确保在声明只是一个重载的情况下,它是真的吗?最后一句:“访客1和访客2的所有访问都是隐藏的”->访客1::访问(B&)
也是隐藏的,或者只是过载了?另外,你能帮我补充一下我刚才添加的“附加问题”吗?@Johannes我添加了它。非常感谢。我不会猜到编译器没有检测到所有隐藏的名称,答案很清楚。让我们更改代码,以便visitor3
仅继承visitor1
(struct visitor3:public visitor1
)(并且不做任何更改)并遵循您的答案。现在,visitor3::visit(B&)
没有重载visitor1::visit(A&)
(“同一范围内没有重载”),所以它应该隐藏visitor::visit(A&)
,对吗?为什么编译器没有警告我要隐藏呢?我不知道(或关心)为什么编译器没有警告你关于合法和定义良好的代码。更改基类不会改变visitor3
具有visit
定义的事实,因此编译器不会查看基类的其他定义。可能它认为在这种简单的情况下(继承一次并仅重载一个具有完全相同签名的函数),这是显而易见的,我知道我在做什么(隐藏访问者1::访问(B&)
)?