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&)
)?