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

发布于 2024-10-14 21:37:43 字数 618 浏览 5 评论 0原文

隐藏规则背后的基本原理是什么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;无效 f(双精度); } // B::f(int) 不隐藏
    

那么,为什么会有隐藏规则?

What's the rationale behind the hiding rule in C++?

class A { void f(int); }
class B : public A { void f(double); } // B::f(int) is hidden
  • If it is a meaningful feature I think it should also be possible to hide functions without defining new functions with the same name: something like this:

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

but this is not possible.

  • I don't think it simplifies compilers job, since compilers must anyway be able to unhide functions when you explicitly use the using directive:

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

So, how come there is a hiding rule?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

沙与沫 2024-10-21 21:37:43

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

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

有关此问题的详细讨论可以在此处< /a>...

It's an hairy question, but apparently the idea is that this hiding feature helps avoiding subtle bugs when making changes to a base class (that could otherwise "steal" calls that before would have been handled by the derived class). Still a change in a base class can influence the result of compilation of derived classes so I don't think I understand 100% this explanation.

I agree that this topic is so frequently discussed that probably the hiding actually increases the amount of "surprises" in C++ programmers.

A detailed discussion about this issue can be found here...

提赋 2024-10-21 21:37:43

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

隐藏在某些方面对你有帮助。

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

并且您不会因某些意外将带有参数 false 的调用定向到具有形式参数 void* 的基类方法而与重载解析发生冲突。这样的事情。

干杯&呵呵,

i don't know the original rationale, but since hide or not hide are about equally bad choices wrt. to functions, i'm guessing the rationale is to have uniform rules: the same as for names defined in nested curly-braces scopes.

the hiding helps you in some ways.

adding a method to a base class will by default not affect overload resolution for a derived class.

and you do not run afoul of overload resolution by some mishap directing your call with say argument false, to a base class method with formal argument void*. such things.

cheers & hth.,

書生途 2024-10-21 21:37:43

我确信我见过 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
}

现在,在 Base 中添加 void f(int);,以及其含义主要变化 - 它调用 Base::f 因为 int 更适合 char - 它是整数提升而不是标准转换。

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

不需要“隐藏”关键字,因为没有隐藏“f”的类似情况当 Derived 中重载时,来自 Base。

顺便说一句,我选择了类型,而 char 是故意不协调的。您可以使用 intunsigned int 而不是 intchar 来获得更微妙的情况。

I'm sure I've seen this case offered by a C++ bigwig, not sure which:

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
}

Now, add void f(int); to Base, and the meaning of main changes - it calls Base::f because int is a better match for char - it's an integer promotion rather than a standard conversion.

It's not clear whether that change to the base would really be intended by the programmer to catch calls with char, so requiring using to be explicit means the default behavior is that the change doesn't affect the calling code. I believe it's a marginal call, but I think the committee decided that base classes in C++ were fragile enough as they are, without this too :-)

There's no need for a "hide" keyword because there's no comparable case for hiding "f" from the Base when it isn't overloaded in Derived.

Btw, I've chosen the types, and char is deliberately incongruous. You can get more subtle cases with int vs unsigned int rather than int vs char.

阳光下的泡沫是彩色的 2024-10-21 21:37:43

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

#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::fooB::foo 因为以下行匹配两个签名:

foo(a);

Another reason for hiding base class's member function (with same name but different signatures) might be due to ambiguity caused by optional parameters. Consider the following example:

#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;
}

If the foo method in base class hadn't become hidden, it wouldn't be possible for compiler to decide whether A::foo should be called or B::foo since the following line matches both signatures:

foo(a);
小猫一只 2024-10-21 21:37:43

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

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 都不会报告错误。但是,当您在 B<1> 实例上调用方法 g() 时,它们会指示错误。因此,隐藏规则可以更简单地检查您的代码是否有效。

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

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;
}

Probably, the reason is template specialization. I give you an example:

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(); }
};

The template class B has a method f(), but until you don't create an instance of the class B you don't know the signature. So the call this->f() is anytime "legal". Both GCC and CLang don't report error until you create the instance. But when you call the method g() on a B<1> instance they indicate the error. So the hiding rule keep simpler to check if your code is valid.

I report the last part of code used in my example.

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文