为什么 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
Why does C++ need the scope resolution operator?
提问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 ::a
as 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
}
}
}
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::c
is 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
回答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::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->
.
在
N::m
既不是N
也不m
是有值的表达式中;N
和m
是编译器已知的名称,并::
执行(编译时)范围解析而不是表达式评估。可以想象允许 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.
作用域解析运算符(::)用于在类外定义函数,或者当我们想要使用全局变量但又具有同名的局部变量时。