フレンド宣言のスコープについて

このQ&Aのポイント
  • フレンド宣言のスコープについての疑問
  • C++プライマー第4版で紹介されているフレンド宣言のスコープについての説明
  • gccでのコンパイルエラーについての疑問
回答を見る
  • ベストアンサー

フレンド宣言のスコープがわかりません。

フレンド宣言のスコープがわかりません。 #include <iostream> class X { friend class Y; friend void f() { std::cout << "f()" << std::endl; } }; //class Y; //void f(); class Z { Y *ymem; void g() { ::f(); } }; int main() { ::f(); return 0; } C++プライマー第4版を読んでいます。511ページに上記のプログラムがあり、 「フレンドで導入されたクラスと関数(定義または宣言)は、すでに宣言されたものとして使うことができる。」 と説明されています。 しかし、g++(gcc4.4.1)でコンパイルするとエラーになります。コメント部分を外すと実行できます。 C++プライマーが正しいのか、gccが正しいのか、私が思い違いをしているのか、わかりません。 ご存知の方はいませんか。

noname#114276
noname#114276

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

どう見たってgccの方が正しいに決まってます。 > friend class Y; これはclass Y をclass Xのフレンドだと宣言してるだけで、class Yの実体はありません。 > friend void f() > { std::cout << "f()" << std::endl; } > }; これは確かにフレンド関数f()の実体がここにあるように見えますが、これは単なる関数の処理部の記述をここでしているだけであって、外部から見たf()の宣言がここにあるわけではありません。 そもそもフレンド宣言は外部のclassなり関数からそのclass内メンバへのアクセスを許容する宣言なので、classなり関数の宣言は外部に無くては意味ありません。 class Zの中で使われてるYやf()も、main()の中で使われてるf()も、どちらもclass Xの中には直接アクセスできないのだから、外部に宣言がないとエラーになるのは自明です。 書籍とかに書かれてるコードは(著者にとって)自明な部分は省かれてることがままありますから、それをそのままコンパイルして通るという保証はありません。(ま、思い違いとかチェック漏れの場合もあるでしょういけど)

noname#114276
質問者

お礼

回答ありがとうございます。 gccが正しいとよくわかりました。 magicalpassさん、ありがとうございます。

関連するQ&A

  • C++のクラスについて

    /*以下のコメントがある行では何故、コンストラクタ(class2::class2)を指定出来ないのですか? デストラクタ(class2::~class2)の場合も問題なくコンパイルが通り、実行できます (http://codepad.org/1oJkxjyZ の23行目) 開発環境 Windows XP SP3 コンパイラ:GCC 実行結果 class1のコンストラクタ class2のコンストラクタ aiueoの実行 class2のデストラクタ class1のデストラクタ */ #include<iostream> class class1; class class2; class class1{ public: class1(); ~class1(); private: class2*pointer; }; class class2{ public: class2(); ~class2(); void aiueo(); }; class1::class1(){ std::cout<<"class1のコンストラクタ"<<std::endl; pointer=new class2(); pointer->aiueo(); //aiueoを~class2に置き換えてもコンパイル出来るが、class2だとエラーが出る } class1::~class1(){ delete pointer; std::cout<<"class1のデストラクタ"<<std::endl; } class2::class2(){ std::cout<<"class2のコンストラクタ"<<std::endl; } class2::~class2(){ std::cout<<"class2のデストラクタ"<<std::endl; } void class2::aiueo(){ std::cout<<"aiueoの実行"<<std::endl; } int main(){ class1 test1; return 0; }

  • C++について。

    現在”猫でもわかるプログラミング”のC++編をSDKと共に勉強している身です。 現在第22章、第23章を勉強中です。 22章 http://www.kumei.ne.jp/c_lang/cpp/cpp_22.htm 23章 http://www.kumei.ne.jp/c_lang/cpp/cpp_23.htm 作業環境はVisual Studio 2005.net C++です 22章でのプログラムを作成し、実行した結果エラーが出てしまいました。 ソースです #include <iostream> class xy_position { int x; int y; public: xy_position(int x = 0, int y = 0){ xy_position::x = x; xy_position::y = y; } int X() const {return x;} int Y() const {return y;} }; ostream& operator << (ostream& o, const xy_position& p) { return o << "(" << p.X() << "," << p.Y() << ")"; } int main(void) { xy_position a(50, 60), b; std::cout << a << b << std::endl; return 0; } (17):error C2143: 構文エラー : ';' が '&' の前にありません。 (17):error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません (17):error C2065: 'o' : 定義されていない識別子です。 (17):error C2059: 構文エラー : 'const' (18):error C2143: 構文エラー : ';' が '{' の前にありません。 (18):error C2447: '{' : 対応する関数ヘッダーがありません (旧形式の仮引数リスト?) (26):error C2679: 二項演算子 '<<' : 型 'xy_position' の右オペランドを扱う演算子が見つかりません (または変換できません)。 このようなエラーが出てしまいました。 もちろんソースは全て同様に書いています。 この”猫でも”で使用しているコンパイラと異なるために出たエラーでしょうか? それに単に cout << のように記述するとエラーが出てしまい、 std::cout << のように記述しなければ通りません。 また、エラーとは別の質問になってしまいますが、プログラム中に int X() const {return x;} という記述がありますが、このconstの意味が分かりません。 単純に return x が変更不可能という意味でしょうか? 次に23章についての質問です。 ここでもソースは同じなのに以下のようなエラーが出てしまいます。 ソースです。 #include <iostream> int main(void) { int x=10, y=15, z=20; std::cout << "16進表示" << std::endl; std::cout.setf(ios::hex); std::cout << x << std::endl; std::cout << y << std::endl; std::cout << z << std::endl; std::cout.unsetf(iostream::hex); std::cout << "8進数" << std::endl; std::cout.setf(ios::oct); std::cout << x << std::endl; std::cout << y << std::endl; std::cout << z << std::endl; return 0; } (8):error C2653: 'ios' : 識別子がクラス名でも名前空間名でもありません。 (8):error C2065: 'hex' : 定義されていない識別子です。 (13):error C2653: 'iostream' : 識別子がクラス名でも名前空間名でもありません。 (15):error C2653: 'ios' : 識別子がクラス名でも名前空間名でもありません。 (15):error C2065: 'oct' : 定義されていない識別子です。 これも何か設定をしなければいけないのでしょうか? なにぶんC++は・・・というかオブジェクト指向の言語は初心者なもので疑問も多いですorz

  • 変数の隠蔽とスコープ

    いつまでも初心者のままじゃ駄目だなあと思い, 用事のついでに本屋まで行って 評価が高いらしい http://www.amazon.co.jp/exec/obidos/ASIN/4797328541/Lvdrfree-22?dev-t=D1KDF7Q74DD3A2%26camp=2025%26link_code=xm2 を100ページほど立ち読みしてみた。(買ってません) で、まあ内容を理解できているかは別として 可視性とアクセス制御という話があって Java や C#の時の知識から 以下のコードの出力結果は一応理解できます。 折角なので 質問もコードの中に書いてみました。 ========================== #include <iostream> int a = 5; class fuga{ public: int a; fuga(){ a = 3; } }; class hoge : fuga{ //実際の書籍では public fugaだったような public: void printa(){ std::cout << a << std::endl; //コンパイル通っちゃったけど,ここからグローバル変数a(==5)にアクセスする方法はあるの? } }; int main(){ hoge* p = new hoge; p->printa(); std::cout << a << std::endl; delete p; // 3 // 5 }

  • 無名ネームスペース中のstatic宣言について

    お世話になります。 以下のように無名ネームスペース内でstatic定数を宣言することに 何か問題はあるでしょうか? QACという静的コードチェックツールで 「無名ネームスペース中のstatic宣言」と 警告が出てしまいます。 test.h ----------------------- class Test{ void testFunc(); }; test.cpp ------------------------ namespace { static const int i = 3; } void Test::testFunc(){ std::cout << i << std::endl; }

  • C++

    今、下のようなプログラムを作っています #include <iostream> #include <iostream> using namespace std; int i=0, c=0, n; char str[10]; class X16karax10{ //16進から10進ヘ public: void keisan(); }; void X16karax10::keisan(void){ cout<<"16進を入力して下さい"<<endl; cout<<"英数字は大文字で入力してください(F→○ f→×)" <<endl; scanf("%s",str); while(str[i] != '\0'){ n = n * 0x10; c = str[i++]; if((c >= '0') && (c <= '9')){ n += c - '0'; } else if((c >= 'A') && (c <= 'F')){ n += c - 'A' + 10; } } cout<<("%d\n",n)<<"です\n"<<endl; } int main(){ for(i=0; ; i++){ X16karax10 p; p.keisan(); } } 16進を十進に変えるものなのですがreturn 0を使うと「X16karax10::keisan()' は値を返せない」と、でてしまうのですがどうしたらよいでしょうか?

  • C++のファイルの分割について教えてください。

    分割したプログラムの書き方を練習中なのですが、 下のようなプログラムを書いて、ビルドしようとしたら失敗します。 どこが悪いのか、教えていただけないでしょうか? (5)\test30\Debug\test30.exe : fatal error LNK1120: 外部参照 1 が未解決です。 1>test30 - エラー 2、警告 0 ========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ========== //test30.cpp #include <iostream> #include "sub.h" int main(void) { std::cout<<"メインプログラムです。"<<std::endl; sub1(); sub2(); return 0; } ------------------------------------------------------------- //sub1.cpp #include <iostream> void sub1(void) { std::cout<<"サブ1です。"<<std::endl; } ------------------------------------------------------------- //sub2.cpp #include <iostream> void sub1(void) { std::cout<<"サブ2です。"<<std::endl; } --------------------------------------------------------------- //sub.h void sub1(void); void sub2(void);

  • スコープ外でのアドレスの参照についての疑問

    C++を勉強していて解らないことがあったので質問させていただいたのですが、 とあるスコープで生成したインスタンスを、 スコープ外で参照しても問題なく値が取り出せるのですけども、 これは処理的には問題ないのでしょうか? 例のソースを以下に示します。 struct Hoge {  int a, b; }; void testA(){  Hoge *hoge;  if( true ){   Hoge tmp;   tmp.a = 1;   tmp.b = 2;   hoge = &tmp;  }  std::cout << hoge->a << "," << hoge->b << std::endl; } void testB(){  Hoge *pHoge;  if( true ){   Hoge *pTmp = new Hoge();   pTmp->a = 1;   pTmp->b = 2;   pHoge = pTmp;  }  std::cout << pHoge->a << "," << pHoge->b << std::endl;  delete pHoge;  pHoge = NULL; } 上記の場合、どちらも画面に 1,2 と出力されますが、 アドレスが上書きされていないだけで今の時点では偶然エラーが出ないけども潜在的なバグがあったり、 処理的にいつ落ちるかわからないなどの問題はあったりしますか? ご存知の方がいらっしゃいましたらアドバイスをお願いします

  • プログラミング言語Cとプログラミング言語C++

    プログラミング言語Cとプログラミング言語C++の違いって何ですか? あと、プログラミング言語C++についていくつか質問があります。 #include <iostream> using namespace std; void main(){ cout << "Hello world!" << endl; } このプログラムについて質問なんですが、iostreamってプログラミング言語Cで言うstdio.hのことですか? using namespace stdって何ですか? あと、 cout <<"Hello world!"って何ですか?

  • 【C++】アドレス演算子について質問です。

    アドレス演算子について質問です。 下記のように"&"を関数名の前に付けた場合下記のように出力されます。 &グローバルメソッド:002E1226 &クラス::メンバメソッド:1 1行目はグローバルメソッドなので実態が存在するのでメソッドのアドレスが表示されている。 2行目は実態が存在しないと思うのですが、あってますでしょうか? また、何故1が表示されてしまうのでしょうか? -------------------------------------------------------- #include "stdafx.h" #include <iostream> using namespace std; class Class1{ public: void f(){ return; } }; void Func1(){ return; } int main() { cout << "&グローバルメソッド:" << &Func1 <<endl; cout << "&クラス::メンバメソッド:"<< &Class1::f <<endl; getchar(); return 0; }

  • char型変数のアドレスを coutで表示するには

    #include <iostream> using namespace std; int main() { bool b; int i; short s; long l; float f; double d; char c; //上で宣言した変数のアドレスを表示 cout << "bool &b " << &b << endl; cout << "int &i " << &i << endl; cout << "short &s " << &s << endl; cout << "long &l " << &l << endl; cout << "float &f " << &f << endl; cout << "double &d " << &d << endl; cout << "char &c " << &c << endl; //「char &c 」とのみ表示される cout << '\n'; //char型のみ printf で再表示 printf("char &c %p\n", &c); //「char &c ********」と表示される return 0; } 上のプログラムを実行すると cout << "char &c " << &c << endl; のところだけ、アドレスが表示されません。 printfを使えば、char型の変数のアドレスも表示されるのですが…。 coutを使ってchar型のアドレスを表示させるにはどうすればいいのでしょうか。 よろしくお願いします。

専門家に質問してみよう