C++アドレス演算子についての質問

このQ&Aのポイント
  • C++のアドレス演算子について質問です。センセーショナルなタイトル
  • アドレス演算子の使い方や動作に関して、特にクラスのメンバメソッドにおける挙動について疑問があります。
  • グローバルメソッドとクラスのメンバメソッドにおけるアドレスの出力結果の違いについて説明してください。
回答を見る
  • ベストアンサー

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

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

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

(1) 1 になる理由 std::ostream の operator<< がメンバ関数ポインタに対する overload を定義していないので、 規格 [conv.bool] の boolean conversion 規則が適用されて &Class1::f は (bool)&Class1::f に変換されます。 &Class1::f は null ではないので bool 的には true になります。 そして、ostream は true に対して 1 を出力するので、上のコードで 1 が表示されるのです。 なので、この出力に関しては処理系依存ではなくて、(規格準拠の処理系なら) 常に 1 が出力されるべきかと思います。 (2) 中身の見方 メンバ関数ポインタの「内容」を知りたければ union などを使って無理矢理 void* に変換するとか。。(規格的にはメンバポインタから通常ポインタへのキャストは定義されていません。) ------------------ union{ void (Class1::*mfp)(); void* ptr; } conv = { &Class1::f }; cout<<"&クラス::メンバ関数"<<conv.ptr<<endl; ------------------ 大体の処理系では、メンバ関数ポインタの「内容」はやはり実体のアドレスの様です。但し、「内容」が実体のアドレスなのか、或いはもっと違う種類のデータなのかは、既に回答された方のいう通り処理系依存なので、常にアドレスが得られるとは限りません。 (3) 実体はある > 2行目は実態が存在しないと思うのですが、あってますでしょうか? メンバ関数にもちゃんと関数実体があります! なかったら実行できないではありませんか…。 (3) 後、用語が気になるので… * 実態→実体 * グローバルメソッド→グローバル関数 (メソッドは普通メンバ関数の事です) * メンバメソッド→メソッド or メンバ関数 (C++ 的にはメンバ関数です)

参考URL:
http://stackoverflow.com/questions/2064692/how-to-print-function-pointers-with-cout
haraheri31
質問者

お礼

用語の説明まで大変ありがとうございました。 C++を学んでいるところなのですが、 調べれば調べる程奥深く、驚いています。 詳しいご説明感謝します。

その他の回答 (1)

回答No.1

普通の関数(この例ではFunc)へのポインタと メンバ関数へのポインタとを同列に扱ってはいけません。 メンバ関数へのポインタの中にメンバ関数のアドレスが入っているとは言えないのです。 以下のコード、Visual C++ では 1 がふたつ出力されます。 メンバ関数のアドレスが入っているとすると説明できなくなります。 #include <iostream> using namespace std; class Class1{ public: void f() {} void g() {} }; int main() { cout << "&クラス::メンバメソッド:"<< &Class1::f <<endl; cout << "&クラス::メンバメソッド:"<< &Class1::g <<endl; } ならば何が入っているか、は "コンパイラの勝手"です。 C++言語規格では"どう振る舞うか"は書かれていますが、 "どんな機械語に展開されるか"には一言も言及していません。 なので、 > 1行目はグローバルメソッドなので実態が存在するのでメソッドのアドレスが表示されている。 > 2行目は実態が存在しないと思うのですが、あってますでしょうか? > また、何故1が表示されてしまうのでしょうか? この質問自体が意味を成しません。 「コンパイラがそんな機械語を吐いたから」です。

関連するQ&A

  • 【C++】関数ポインタの使い方

    関数ポインタの使い方で悩んでいます。 下記の (1)のようにグローバルメソッドとして定義したメソッドを関数ポインタに代入することは出来るのですが、 (2)のようにクラスのメンバメソッドとして定義したメソッドは関数ポインタに代入することは出来ませんでした。 Error:バインドされた関数へのポインターは関数の呼び出しにのみ使用できます。 というエラーが発生します。 関数ポインタに外部参照でメソッドを代入することは出来ないのでしょうか? -----(1)------------------------------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; int f(int a, int b){ return a * b; } int _tmain(int argc, _TCHAR* argv[]) { typedef int (* FUNC_POINTER)(int, int); FUNC_POINTER fp; fp = f; cout << fp(1,2) <<endl; getchar(); return 0; } ------------------------------------------------------------------------- -----(2)------------------------------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; class MPointerList{ public: int f(int a, int b){ return a * b; } }; int _tmain(int argc, _TCHAR* argv[]) { typedef int (* FUNC_POINTER)(int, int); FUNC_POINTER fp; //fp = f; MPointerList mP; fp = mP.f; cout << fp(1,2) <<endl; getchar(); return 0; } -------------------------------------------------------------------------

  • 【C++】関数ポインタの代入

    C++の関数ポインタについて質問です。 下記のように関数ポインタを宣言し、3通りの代入を行ってみました。 (3)のように関数名の頭に&を付けた場合と(2)のように&を付けなかった場合で 全く動きが同じになってしまうのですが、何故なのでしょうか? ------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; void Func1(){ cout<<"Func1が呼ばれました。"<<endl; return; } int main() { //(1) void (*fp1_1)(); fp1_1 = Func1; fp1_1(); //(2) void (*fp1_2)()=Func1; fp1_2(); //(3) void (*fp1_3)()=&Func1; fp1_3(); getchar(); return 0; }

  • 仮想関数でのオーバーライドでの質問

    仮想関数でのオーバーライドでの質問 二つの派生クラスを定義したのですが、一つ目のクラスのメソッドが実行されないで困っています。 下記にソースを載せておきます。 どこが原因でそうなるのかご指摘お願いします。 /* 継承 */ #include <iostream> using namespace std; class Var { private: int value; static Var* re; public: // 静的関数 static bool func() { // 内部で同一の関数を呼び出す re->show(); return true; } virtual show() { cout << "message00" << "moji" << endl; } // 自身のポインタを取得 Var() { re = this; } }; Var* Var::re = NULL; class Msg01 : public Var { private: int value; public: show(void) { cout << "message01" << "moji" << endl; } }; class Msg02 : public Var { private: int value; public: show(void) { cout << "message02" << "moji" << endl; } }; int main() { Msg01 val; Msg02 msva; val.func(); msva.func(); getchar(); return 0; } /------------------------------------------------------/ 実行結果 message02moji message02moji /------------------------------------------------------/ message01mojiが表示されるはずなんですが表示されないでいます。 Msg02を宣言したためこのようになってしまったんでしょうか?

  • C++でEXEを作成してCGI-BINで動作させてますが、ブラウザからの入力を受ける方法がわからん

    自前のEXEでTESTとブラウザに表示させることに成功しました =========-- #include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { cout << "Content-type: text/plain" << endl; cout << endl; cout << "test" << endl; return 0; } ==============--- さて、POSTメソッドで受けた内容や、ウラウザの種類やREFERなどはどうやってEXEで取得するのかがわかりません。教えてください。

    • ベストアンサー
    • CGI
  • C/C++関数間でのStringクラスの扱い

    以下のようなコードを実行してみましたが思い通りに動いてくれません. "sample"という文字列がstrへとコピーされると思ったのですが. stringクラスのc_str()メソッドはconst char*だと言っているので無理矢理キャストしたのが原因でしょうか.stringクラスは記憶領域を自動で変更してくれるのではないのですか.それともこの挙動は仕様ですか. -------- 以下コード -------- #include <iostream> #include <string> using namespace std; int func(char *); int main(void) {     string str("");     func((char *)str.c_str());     cout << "String: " << str << endl;     return EXIT_SUCCESS; } int func(char *buf) {     buf = "sample";     return 0; } -------- 以上コード --------

  • 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++

    今、下のようなプログラムを作っています #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()' は値を返せない」と、でてしまうのですがどうしたらよいでしょうか?

  • operator * について

    掛け算ではない方の operator * についての質問です。 下のソースを見てください。関数func()内で、(*this)[idx]というやり方と、直接operator [] を呼び出すやり方を試しています。(*this)[idx]は自分のコピーを作ってしまわないでしょうか?このようなやり方は正しいでしょうか。というのが第1の質問です。 さらに、CTestで operator * を定義していますが、(*this)[idx]で呼び出されません。なぜなのでしょうか。というのが第2の質問です。 どうぞよろしくお願いいたします。 class CTest : public vector<int> { public: CTest() : vector<int>() { push_back(1); push_back(2); push_back(3); } void func() { #if 1 // 質問1 この書き方をしてもコピーが作られないかどうか? cout<<(*this)[0]<<endl; cout<<(*this)[1]<<endl; cout<<(*this)[2]<<endl; #else cout<<operator[](0)<<endl; cout<<operator[](1)<<endl; cout<<operator[](2)<<endl; #endif } CTest& operator * () { // 質問2 なぜこのオペレータが呼び出されないのか cout<<"???"<<endl; return *this; } }; void main(void) { CTest inst; inst.func(); }

  • 添字演算子

    #include <iostream> class hoge{ private: int a; public: hoge(){ a = 0; } int operator+(int fuga){ a = a + fuga; return a; } int operator[](int fuga){ return 1; } }; int main(){ hoge* p; p = new hoge; std::cout << ((*p) + 5) << std::endl; std::cout << ((*p)[1] ) << std::endl; // 5 // 1 // std::cout << ((*p) [] 1); エラーです。何故ですか? }

  • ラムダ式を関数に渡したいのですが

    Class1からClass2にある関数の引数にラムダ式で関数を渡すようなプログラムを作ろうと思い、以下のようにコードを記述しました。 #include <iostream> class Class1 { int i = 0; void func() { std::cout << "Hello world" << std::endl; } void init() { Class2 *class2 = new Class2(); class2->setFunc([this] { func(); i++; }()); } }; class Class2 { void(*mFunc)(); void runFunc(){ mFunc(); } public: void setFunc(void func()) { mFunc = func; } }; すると class2->setFunc([this] { func(); i++; }()); のところで「型"void"の引数は型"void(*)()"のパラメーターと互換性がありません」というエラーが発生してしまいます。 キャプチャにthisを渡したラムダ式を他のクラスの関数ポインタのような変数に代入させるようにしたいのですがどのように記述したらできますか

専門家に質問してみよう