Why does C++ need the scope resolution operator?

2019-01-04 10:40发布

(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?

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 ..

7条回答
干净又极端
2楼-- · 2019-01-04 10:52

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

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 idea what 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.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-01-04 10:54

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

The reason is given by Stroustrup himself:

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

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

Moreover it's true that

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

indeed

In N::m neither N nor m are expressions with values; N and m are 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 ->.

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

查看更多
唯我独甜
4楼-- · 2019-01-04 10:55

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

#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;
}
查看更多
甜甜的少女心
5楼-- · 2019-01-04 10:57

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;
}
查看更多
我想做一个坏孩纸
6楼-- · 2019-01-04 11:07

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.

查看更多
The star\"
7楼-- · 2019-01-04 11:10

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 ::a as shown below:

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.


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

Who said syntax like a.b::c is not legal?

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):

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:

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.A::f(); //ok - explicitly selecting the hidden function using scope resolution

Demo at ideone

查看更多
登录 后发表回答