为什么 C++ 需要作用域解析运算符?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9338217/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:41:36  来源:igfitidea点击:

Why does C++ need the scope resolution operator?

c++operatorslanguage-designscope-resolution

提问by Karu

(I know what the scope resolution operator does, and how and when to use it.)

(我知道范围解析运算符的作用,以及如何以及何时使用它。)

Why does C++ have the ::operator, instead of using the .operator for this purpose? Java doesn't have a separate operator, and works fine. Is there some difference between C++ and Java that means C++ requires a separate operator in order to be parsable?

为什么 C++ 有::运算符,而不是.为此目的使用运算符?Java 没有单独的运算符,并且工作正常。C++ 和 Java 之间是否有一些区别,这意味着 C++ 需要一个单独的运算符才能进行解析?

My only guess is that ::is needed for precedence reasons, but I can't think why it needs to have higher precedence than, say, .. The only situation I can think it would is so that something like

我唯一的猜测是::出于优先级原因需要这样做,但我想不出为什么它需要比.. 我能想到的唯一情况是这样的事情

a.b::c;

would be parsed as

将被解析为

a.(b::c);

, but I can't think of any situation in which syntax like this would be legal anyway.

,但我想不出像这样的语法在任何情况下都是合法的。

Maybe it's just a case of "they do different things, so they might as well look different". But that doesn't explain why ::has higher precedence than ..

也许这只是“他们做不同的事情,所以他们看起来也可能不同”的情况。但这并不能解释为什么::..

采纳答案by Nawaz

Why C++ doesn't use .where it uses ::, is because this is how the language is defined. One plausible reason could be, to refer to the global namespace using the syntax ::aas shown below:

为什么 C++ 不在.它使用的地方使用::,是因为这就是语言的定义方式。一个合理的原因可能是,使用::a如下所示的语法来引用全局命名空间:

int a = 10;
namespace M
{
    int a = 20;
    namespace N
    {
           int a = 30;
           void f()
           {
              int x = a; //a refers to the name inside N, same as M::N::a
              int y = M::a; //M::a refers to the name inside M
              int z = ::a; //::a refers to the name in the global namespace

              std::cout<< x <<","<< y <<","<< z <<std::endl; //30,20,10
           }
    }
}

Online Demo

在线演示

I don't know how Java solves this. I don't even know if in Java there is global namespace. In C#, you refer to global name using the syntax global::a, which means even C# has ::operator.

我不知道Java如何解决这个问题。我什至不知道 Java 中是否有全局命名空间。在 C# 中,您使用语法来引用全局名称global::a,这意味着即使 C# 也有::运算符。



but I can't think of any situation in which syntax like this would be legal anyway.

但我想不出像这样的语法在任何情况下都是合法的。

Who said syntax like a.b::cis not legal?

谁说语法 likea.b::c不合法?

Consider these classes:

考虑这些类:

struct A
{
    void f() { std::cout << "A::f()" << std::endl; }
};

struct B : A
{
    void f(int) { std::cout << "B::f(int)" << std::endl; }
};

Now see this (ideone):

现在看这个(ideone):

B b;
b.f(10); //ok
b.f();   //error - as the function is hidden

b.f()cannot be called like that, as the function is hidden, and the GCC gives this error message:

b.f()不能这样调用,因为该函数是隐藏的,并且 GCC 给出了以下错误消息:

error: no matching function for call to ‘B::f()'

In order to call b.f()(or rather A::f()), you need scope resolution operator:

为了调用b.f()(或更确切地说A::f()),您需要范围解析运算符:

b.A::f(); //ok - explicitly selecting the hidden function using scope resolution

Demo at ideone

在ideone上演示

回答by Nicol Bolas

Because someone in the C++ standards committee thought that it was a good idea to allow this code to work:

因为 C++ 标准委员会的某个人认为让这段代码工作是个好主意:

struct foo
{
  int blah;
};

struct thingy
{
  int data;
};

struct bar : public foo
{
  thingy foo;
};

int main()
{
  bar test;
  test.foo.data = 5;
  test.foo::blah = 10;
  return 0;
}

Basically, it allows a member variable and a derived class type to have the same name. I have no ideawhat someone was smoking when they thought that this was important. But there it is.

基本上,它允许成员变量和派生类类型具有相同的名称。当他们认为这很重要时,我不知道有人在抽什么烟。但它就在那里。

When the compiler sees ., it knows that the thing to the left must be an object. When it sees ::, it must be a typename or namespace (or nothing, indicating the global namespace). That's how it resolves this ambiguity.

当编译器看到 时.,它知道左边的东西一定是一个对象。当它看到 时::,它必须是一个类型名或命名空间(或什么都没有,表示全局命名空间)。这就是它如何解决这种歧义。

回答by dasblinkenlight

Unlike Java, C++ has multiple inheritance. Here is one example where scope resolution of the kind you're talking about becomes important:

与 Java 不同,C++ 具有多重继承。这是一个示例,其中您所谈论的范围分辨率变得很重要:

#include <iostream>
using namespace std;
struct a
{
    int x;
};
struct b
{
    int x;
};
struct c : public a, public b
{
    ::a a;
    ::b b;
};
int main() {
    c v;
    v.a::x = 5;
    v.a.x = 55;
    v.b::x = 6;
    v.b.x = 66;
    cout << v.a::x << " " << v.b::x << endl;
    cout << v.a.x << " " << v.b.x << endl;
    return 0;
}

回答by manlio

Why does C++ have the :: operator, instead of using the . operator for this purpose?

为什么 C++ 有 :: 运算符,而不是使用 . 运营商为此目的?

The reason is given by Stroustrup himself:

原因由 Stroustrup 本人给出:

In C with Classes, a dot was used to express membership of a class as well as expressing selection of a member of a particular object.

This had been the cause of some minor confusion and could also be used to construct ambiguous examples. To alleviate this, ::was introduced to mean membership of class and .was retained exclusively for membership of object

在 C with Classes 中,点用于表示类的成员资格以及表示对特定对象的成员的选择。

这是造成一些轻微混淆的原因,也可以用来构建模棱两可的例子。为了缓解这种情况,::被引入意味着类的成员资格,并.专门为对象的成员资格而保留

(Bjarne Stroustrup A History of C++: 1979?1991page 21 - § 3.3.1)

(Bjarne Stroustrup A History of C++: 1979?1991page 21 - § 3.3.1)

Moreover it's true that

此外,这是真的

they do different things, so they might as well look different

他们做不同的事情,所以他们也可能看起来不同

indeed

的确

In N::mneither Nnor mare expressions with values; Nand mare names known to the compiler and ::performs a (compile time) scope resolution rather than an expression evaluation. One could imagine allowing overloading of x::y where x is an object rather than a namespace or a class, but that would - contrary to first appearances - involve introducing new syntax (to allow expr::expr). It is not obvious what benefits such a complication would bring.

Operator .(dot) could in principle be overloaded using the same technique as used for ->.

N::m既不是N也不m是有值的表达式中;Nm是编译器已知的名称,并::执行(编译时)范围解析而不是表达式评估。可以想象允许 x::y 重载,其中 x 是一个对象而不是命名空间或类,但这将 - 与第一次出现相反 - 涉及引入新语法(以允许expr::expr)。这种并发症会带来什么好处并不明显。

操作符.(点)原则上可以使用与->.

(Bjarne Stroustrup's C++ Style and Technique FAQ)

(Bjarne Stroustrup 的C++ 风格和技术常见问题解答

回答by nolandda

Just to answer the final bit of the question about operator precedence:

只是为了回答有关运算符优先级的问题的最后一点:

class A {
public:
  char A;
};

class B : public A {
public:
  double A;
};

int main(int c, char** v)
{
  B myB;
  myB.A = 7.89;
  myB.A::A = 'a';
  // On the line above a hypothetical myB.A.A
  // syntax would parse as (myB.A).A and since
  // (myB.A) is of type double you get (double).A in the
  // next step. Of course the '.' operator has no
  // meaning for doubles so it causes a syntax error. 
  // For this reason a different operator that binds
  // more strongly than '.' is needed.
  return 0;
}

回答by Owen Reynolds

I always assumed C++ dot/:: usage was a style choice, to make code easier to read. As the OP writes "they do different things, so should look different."

我一直认为 C++ dot/:: 用法是一种风格选择,以使代码更易于阅读。正如 OP 所写“他们做不同的事情,所以看起来应该不同。”

Coming from C++, long ago, to C#, I found using only dots confusing. I was used to seeing A::doStuff();B.doStuff();, and knowing the first is a regular function, in a namespace, and the second is a member function on instance B.

从很久以前的 C++ 到 C#,我发现只使用点会让人困惑。我习惯于看到A::doStuff();B.doStuff();,并且知道第一个是命名空间中的常规函数​​,第二个是实例 B 上的成员函数。

C++ is maybe my fifth language, after Basic, assembly, Pascal and Fortran, so I don't think it's first language syndrome, and I'm more a C# programmer now. But, IMHO, if you've used both, C++-style double-colon for namespaces reads better. I feel like Java/C# chose dots for both to (successfully) ease the front of the learning curve.

C++ 可能是我的第五语言,在 Basic、汇编、Pascal 和 Fortran 之后,所以我不认为这是第一语言综合症,我现在更像是一个 C# 程序员。但是,恕我直言,如果你同时使用了两者,命名空间的 C++ 风格的双冒号读起来会更好。我觉得 Java/C# 都选择了点来(成功地)缓解学习曲线的前端。

回答by Vishal Parekh

Scope resolution operator(::) is used to define a function outside a class or when we want to use a global variable but also has a local variable with same name.

作用域解析运算符(::)用于在类外定义函数,或者当我们想要使用全局变量但又具有同名的局部变量时。