C ++:隐藏规则背后的基本原理

时间:2011-01-29 14:28:35

标签: c++ language-design hide rationale

C ++中hiding rule背后的基本原理是什么?

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
    

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


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

5 个答案:

答案 0 :(得分:10)

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

我同意这个话题经常被讨论,可能隐藏实际上增加了C ++程序员的“意外”数量。

有关此问题的详细讨论可以在here ...

找到

答案 1 :(得分:9)

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

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

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

并且你没有通过使用say参数false将你的调用指向带有形式参数void*的基类方法的一些不幸事件来解决重载决策问题。这样的事情。

欢呼&第h。,

答案 2 :(得分:7)

我确信我看过一个C ++ bigwig提供的这个案例,不知道哪个:

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);添加到Base,以及主要更改的含义 - 它会调用Base::f,因为int更适合char - 它是整数提升而非标准转化。

目前还不清楚程序员是否真的希望打算来捕获char的调用,因此要求using显式是指默认行为是更改不会影响调用代码。我认为这是一个微不足道的呼吁,但我认为委员会认为C ++中的基类很脆弱,没有这个: - )

不需要“隐藏”关键字,因为当 重载时,没有类似的情况可以隐藏“f”。

是的,我选择了类型,char故意不合情理。您可以使用int vs unsigned int而不是int vs char来获得更微妙的案例。

答案 3 :(得分: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);

答案 4 :(得分:-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()来电是“legal”。在创建实例之前,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;
}