Why does C++ need the scope resolution operator?

瘦欲@ 提交于 2019-11-26 03:55:30

问题


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


回答1:


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




回答2:


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:


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



回答4:


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)




回答5:


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:


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

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




回答7:


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.



来源:https://stackoverflow.com/questions/9338217/why-does-c-need-the-scope-resolution-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!