问题
(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
neitherN
norm
are expressions with values;N
andm
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 allowexpr::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