为什么C++需要范围解析运算符?

Kar*_*aru 38 c++ language-design operators scope-resolution

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

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

我唯一的猜测是::出于优先原因需要,但我不能认为为什么它需要具有比例如更高的优先级..我能想到的唯一情况就是如此

a.b::c;
Run Code Online (Sandbox Code Playgroud)

将被解析为

a.(b::c);
Run Code Online (Sandbox Code Playgroud)

,但我无法想到任何情况下,这样的语法无论如何都是合法的.

也许这只是"他们做不同的事情,所以他们可能看起来不同"的情况.但这并不能解释为什么::优先级高于..

Nic*_*las 31

因为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;
}
Run Code Online (Sandbox Code Playgroud)

基本上,它允许成员变量和派生类类型具有相同的名称.当他们认为这很重要时,我不知道有人在吸烟.但它确实如此.

当编译器看到时.,它知道左边的东西必须是一个对象.当它看到时::,它必须是一个typename或命名空间(或者什么都没有,表示全局命名空间).这就是解决这种模糊性的方法.

  • @Nawaz:因为这不会给出任何你想要使用**base`的方法. (3认同)
  • @Nawaz:因为引入关键字比引入运算符要困难得多。而`test.foo.blah` 是不明确的;是基类的`blah`还是`thingy`成员的`blah`?Java(据我所知)通过声明它始终是成员来解决这个问题;您只能通过转换类型来获取基类成员变量。 (2认同)
  • @Nawaz:除非您的代码在任何地方使用过标识符`base`.这是完全可能的.由于编译器的关键因素并不难; 这很难,因为它会使*使用*那些关键词破坏.即使特定于上下文的关键字也意味着您不能拥有名为`base`的类型. (2认同)

Naw*_*waz 29

为什么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
           }
    }
}
Run Code Online (Sandbox Code Playgroud)

在线演示

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


但是我无法想到这样的语法无论如何都是合法的.

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

考虑这些类:

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

struct B : A
{
    void f(int) { std::cout << "B::f(int)" << std::endl; }
};
Run Code Online (Sandbox Code Playgroud)

现在看到这个(ideone):

B b;
b.f(10); //ok
b.f();   //error - as the function is hidden
Run Code Online (Sandbox Code Playgroud)

b.f() 不能这样调用,因为函数是隐藏的,GCC给出了这个错误信息:

error: no matching function for call to ‘B::f()’
Run Code Online (Sandbox Code Playgroud)

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

b.A::f(); //ok - explicitly selecting the hidden function using scope resolution
Run Code Online (Sandbox Code Playgroud)

在ideone演示

  • 这并不能解释为什么你不能只说'bAf`而不是'bA :: f`.如果`A`是一个typename而不是一个变量或函数,那么使用`.`很容易就意味着`scope resolution`而不是常规含义. (3认同)
  • 也许吧,但是如果你看了10年就不行了.就个人而言,即使在10年之后,```看起来也更加尴尬. (2认同)

das*_*ght 9

与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;
}
Run Code Online (Sandbox Code Playgroud)

  • 从技术上讲,这不是关于多重继承.它是关于能够为变量命名与派生类相同的名称. (2认同)
  • 引入`::`运算符时,C++没有多重继承.请参阅[Cfront E手册,第22页(pdf中的25)](http://www.softwarepreservation.org/projects/c_plus_plus/cfront/release_e/doc/ReferenceManual.pdf) - `::`正在使用中,但在类的描述中没有多重继承的迹象. (2认同)

man*_*lio 8

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

原因是Stroustrup本人给出的:

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

这是造成一些轻微混淆的原因,也可用于构建含糊不清的例子.为了缓解这一点,::引入了表示类的成员资格并且.仅为对象的成员资格保留

(Bjarne Stroustrup C++历史:1979-1991第21页 - 第3.3.1节)

而且这是真的

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

确实

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

操作员.(点)原则上可以使用与用于的相同技术来重载->.

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