web-dev-qa-db-ja.com

C ++でスコープ解決演算子が必要なのはなぜですか?

(スコープ解決演算子が何をするか、どのように、いつそれを使用するかを知っています。)

この目的で::演算子を使用する代わりに、C++に.演算子があるのはなぜですか? Javaには個別の演算子はなく、正常に動作します。C++とJavaには、C++が個別の演算子を必要とすることを意味します解析可能?

私の唯一の推測は、::が優先順位の理由で必要であるということですが、たとえば.よりも高い優先順位が必要な理由は考えられません。私が考えることができる唯一の状況は、

a.b::c;

として解析されます

a.(b::c);

、しかし、私はこのような構文がとにかく合法である状況を考えることができません。

多分それは「彼らは異なることをするので、彼らは同様に異なって見えるかもしれない」という場合です。しかし、それは::.よりも優先順位が高い理由を説明していません。

38
Karu

C++が_._を使用する場所で_::_を使用しない理由は、これが言語の定義方法だからです。もっともらしい理由の1つは、以下に示すように、構文_::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
           }
    }
}
_

オンラインデモ

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

これを参照してください( ideone ):

_B b;
b.f(10); //ok
b.f();   //error - as the function is hidden
_

b.f()は、そのように呼び出すことはできません。関数が非表示になり、GCCが次のエラーメッセージを表示するためです。

_error: no matching function for call to ‘B::f()’
_

b.f()(またはA::f())を呼び出すには、スコープ解決演算子が必要です。

_b.A::f(); //ok - explicitly selecting the hidden function using scope resolution
_

ideoneでのデモ

29
Nawaz

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

基本的に、メンバー変数と派生クラス型に同じ名前を付けることができます。 アイデアなしこれが重要だと思ったときに誰かが喫煙していたものがあります。しかし、そこにあります。

コンパイラが.、左のものはオブジェクトでなければならないことを知っています。 ::、typenameまたはnamespaceである必要があります(または、グローバルな名前空間を示す何もありません)。それがこの曖昧さを解決する方法です。

30
Nicol Bolas

Javaとは異なり、C++には複数の継承があります。ここで、話している種類のスコープ解決が重要になる1つの例を示します。

#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;
}
9
dasblinkenlight

を使用する代わりに、C++に::演算子があるのはなぜですか。この目的のための演算子?

理由はStroustrup自身によって与えられます:

C with Classesでは、ドットを使用してクラスのメンバーシップを表し、特定のオブジェクトのメンバーの選択を表します。

これはいくつかの小さな混乱の原因であり、あいまいな例を構築するためにも使用できます。これを軽減するには、::はクラスのメンバーシップを意味するために導入され、.は、オブジェクトのメンバーシップ専用に保持されていました

(Bjarne Stroustrup A C++の歴史:1979−1991 21ページ-§3.3.1)

さらに、それは本当です

彼らは異なることをするので、彼らは異なって見えるかもしれません

確かに

N::mNmも値を持つ式ではありません。 Nおよびmはコンパイラーに既知の名前であり、::は、式の評価ではなく(コンパイル時の)スコープ解決を実行します。 xは名前空間またはクラスではなくオブジェクトであるx :: yのオーバーロードを許可することを想像できますが、それは-最初の外観とは反対に-新しい構文の導入を含む(expr::expr)。このような合併症がもたらすメリットは明らかではありません。

演算子.(ドット)は、原則として、->

(Bjarne Stroustrupの C++スタイルとテクニックに関するFAQ

8
manlio

演算子の優先順位に関する質問の最後のビットに答えるためだけに:

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

コードを読みやすくするために、私は常にC++ dot/::使用法がスタイルの選択であると想定していました。 OPが書いているように、「それらは異なることをするので、異なって見えるはずです」

ずっと前のC++からC#に移行して、ドットだけを使用すると混乱することがわかりました。私はA::doStuff();B.doStuff();を見ることに慣れていましたが、1つ目は名前空間の通常の関数であり、2つ目はインスタンスBのメンバー関数であることがわかりました。

C++は、おそらくBasic、Assembly、Pascal、Fortranに続く5番目の言語であるため、最初の言語シンドロームとは思わず、今ではC#プログラマーになっています。しかし、私見では、両方を使用した場合、名前空間のC++スタイルのダブルコロンの方が読みやすくなります。 Java/C#は、学習曲線の前面を(成功して)緩和するために、両方にドットを選択したように感じます。

2
Owen Reynolds

スコープ解決operator(::)は、クラス外の関数を定義するため、またはグローバル変数を使用したいが、同じ名前のローカル変数も持っている場合に使用されます。

1
Vishal Parekh