27

C++中隐藏规则背后的基本原理是什么?

class A { void f(int); }
class B : public A { void f(double); } // B::f(int) is hidden
  • 如果这是一个有意义的功能,我认为也应该可以隐藏函数而不定义具有相同名称的新函数:像这样:

    class B : public A { hide void f(double); }
    

    但这是不可能的。

  • 我不认为它简化了编译器的工作,因为当你明确使用指令时编译器必须能够取消隐藏函数:using

    class B : public A { using A::f; void f(double); } // B::f(int) NOT hidden
    

那么,怎么会有隐藏规则呢?


嗯,这三个答案似乎都很好,并且显示了隐藏规则的不同理由。我不确定我应该接受哪个答案。

4

5 回答 5

12

这是一个棘手的问题,但显然这个想法是这种隐藏功能有助于在对基类进行更改时避免细微的错误(否则可能会“窃取”以前由派生类处理的调用)。基类的变化仍然会影响派生类的编译结果,所以我认为我不能 100% 理解这个解释。

我同意这个话题被如此频繁地讨论,以至于隐藏实际上增加了 C++ 程序员的“惊喜”数量。

可以在此处找到有关此问题的详细讨论...

于 2011-01-29T14:55:18.977 回答
10

我不知道最初的理由,但是因为隐藏或不隐藏是同样糟糕的选择。对于函数,我猜理由是有统一的规则:与嵌套花括号范围中定义的名称相同。

隐藏在某些方面可以帮助您。

默认情况下,向基类添加方法不会影响派生类的重载决议。

并且您不会因某些意外将您的调用与 say 参数false指向具有正式参数的基类方法而发生冲突void*。这样的事情。

干杯&hth.,

于 2011-01-29T15:03:34.817 回答
8

我确定我见过 C++ 大佬提供的这个案例,但不确定是哪个:

struct Base {
    void f(const Base&);
};

struct Derived : Base {
    using Base::f;
    void f(double);
};

int main() {
    Derived d;
    d.f('a'); // calls Derived::f
}

现在,添加void f(int);toBase和 main 更改的含义 - 它调用是Base::f因为int更好地匹配char- 它是整数提升而不是标准转换。

目前尚不清楚程序员是否真的打算对基进行更改以捕获调用char,因此要求using显式意味着默认行为是更改不会影响调用代码。我相信这是一个微不足道的呼吁,但我认为委员会认为 C++ 中的基类已经足够脆弱,没有这个 :-)

不需要“hide”关键字,因为在 Derived中没有重载时,没有类似的情况可以从 Base 中隐藏“f”。

顺便说一句,我已经选择了类型,并且char故意不协调。int您可以使用vsunsigned int而不是intvs获得更微妙的案例char

于 2011-01-29T16:44:20.107 回答
3

隐藏基类的成员函数(具有相同名称但不同签名)的另一个原因可能是由于可选参数引起的歧义。考虑以下示例:

#include <stdio.h>

class A
{
public:
    int foo(int a, int b=0)
    {
        printf("in A : %d, %d\n", a, b);
    }
};

class B : public A
{
public:
    int foo(int a)
    {
        printf("in B : %d\n", a);
        foo(a); //B:foo(a) will be called unless we explicitly call A:foo(a)
        foo(a, 1); // compile error: no matching function for call to B:foo(int&, int)
    }
};


int main()
{
    B b;
    b.foo(10);
    return 0;
}

如果foo基类中的方法没有被隐藏,编译器将无法决定是否A::foo应该调用,或者B::foo因为以下行匹配两个签名:

foo(a);
于 2012-01-16T12:28:33.157 回答
-2

可能,原因是模板专业化。我给你举个例子:

template <int D> struct A { void f() };

template <> struct A<1> { void f(int) };

template <int D>
struct B: A<D>
{
  void g() { this->f(); }
};

模板类 B 有一个方法f(),但是在您不创建类 B 的实例之前,您不知道签名。所以这个电话this->f()在任何时候都是“合法的”。在您创建实例之前,GCC 和 CLang 都不会报告错误。但是当您g()B<1>实例上调用该方法时,它们会指示错误。因此,隐藏规则更容易检查您的代码是否有效。

我报告了我的示例中使用的代码的最后一部分。

int main (int argc, char const *argv[])
{
  B<0> b0; /* valid */
  B<1> b1; /* valid */

  b0.g(); /* valid */
  b1.g(); /* error: no matching function for call to ‘B<1>::f()’ */

  return 0;
}
于 2011-01-31T16:44:28.877 回答