C ++、関数へのポインターとメンバー関数へのポインターの等価性?

StackOverflow https://stackoverflow.com/questions/411114

  •  03-07-2019
  •  | 
  •  

質問

メンバー関数は、通常の関数の特殊なケースであると考えるのに慣れています。メンバー関数は、「this」ポインター、つまりメンバー関数が動作することになっています。私は過去にboost :: functionをこの方法で使用しましたが、問題は発生していません:

boost::function f<(void)(MyObject*, int, int)> = &MyObject::method_that_takes_two_ints;

しかし、メンバー関数ポインタの構文は次のとおりです。

void (MyObject::*f)( int, int ) = &MyObject::method_that_takes_two_ints;

この構文では、「this」パラメーターは表示されません。そのため、メンバー機能へのポインターが実際には別の獣であるかどうか、そしてそのブーストが私のために細部の面倒を見ていました。

「this」パラメータの配置について、標準は何を規定していますか?おそらく私のコンパイラでは、余分な「this」引数が最初に来ますが、他のコンパイラでは最後に来るのでしょうか?私の考え方がコンパイラ(GCC4、VS2005)の処理方法と一致していることは幸運ですか?メンバ関数へのポインタは常に特別なパラメータを持つ関数へのポインタの特別な場合ですか、それともコンパイラはそれらを異なる方法で実装できますか?

役に立ちましたか?

解決

標準では、 this ポインタを配置する場所についてほとんど何も書かれておらず、実際、メンバー関数に対して異なる呼び出し規約を使用することはかなり一般的です。 (つまり、「this」ポインタは単なる最初の引数ではなく、実際には最初の引数とは異なる場所に実際に保存されます)

特に、MSVCはメンバー関数に対して thiscall 呼び出し規約を使用し、他の場所では stdcall を使用します。 http://www.hackcraft.net/cpp/MSCallingConventions/#thiscall の説明それらの違いですが、 thiscall ECX レジスタに this ポインターを格納し、 stdcall は<スタック上のem> all パラメータ。

これらを完全に異なるタイプとして扱う方が間違いなく優れています。メンバー関数へのポインターは、追加のパラメーターを持つ関数へのポインターではなく、 です。

他のヒント

this ポインターは、メンバーへのポインターと共に格納されません(メンバー関数ポインターはこの特殊なケースです)。ただやるなら

void (MyObject::*f)( int, int ) = &MyObject::method_that_takes_two_ints;

保存されるのは、後で提供する必要があるオブジェクトで呼び出されるメンバー関数の情報だけです。呼び出したい場合は、コンパイラが this ポインタを取得するオブジェクトを渡す必要があります。

MyObject o; (o.*f)(1, 2);

メンバー関数ポインターは、(ポイントされる)型が関数型であるメンバーポインターです。標準では、メンバー関数ポインターには独自の「メンバー関数型」がないとされています。彼らが指していること、そしてそれは何らかの形でthisポインタ型を含むでしょう。

int main() {
    typedef void fun() const;
    fun MyObject::*mem_function_ptr = 
        &MyObject::const_method_that_takes_two_ints;
}
そのコードの

fun は関数型です。 「通常」というタイプ機能があります。 member-function-pointerとは対照的に、関数へのポインターは、その型を持つ関数への単なるポインターです。

void foo() { cout << "hello"; }
int main() {
    typedef void fun();
    fun * f = &foo;
}

メンバー関数へのポインターには、その関数型の最上位に追加のメンバーポインターレベルがあります。

this ポインターに関するものと、それが指すオブジェクトとの関係(技術的ではなく、理論的なもの):

各メンバー関数には、 MyObject&amp; または MyObject const&amp; 型を持つ implicit object parameter という非表示パラメーターがあります。 constまたはnonconstメンバー関数。メンバー関数を呼び出すオブジェクト o は、パラメーターに渡される暗黙のオブジェクト引数です。メンバー関数の呼び出し方法を記述する規則を構成する標準の理論では、暗黙的なオブジェクトパラメーターは最初の隠されたパラメーターです。これは概念的なものであり、実装の実際のケースを意味するものではありません。暗黙のオブジェクト引数は、その暗黙のオブジェクトパラメータにバインドされ、暗黙の変換を引き起こす可能性があります(したがって、非constオブジェクトでconstメンバー関数を呼び出すと、修飾変換は MyObject からに変換されますMyObject const&amp; 。これが、const関数を呼び出すよりも、const関数よりも非const関数の方が適切な選択になる理由です。たとえば、次のコードで言うことができます:

struct A {
    operator int() const { return 0; }
};

int main() { 
    A a;
    int i = a; // implicit conversion using the conversion function
}

タイプ A の暗黙のオブジェクト引数 a は、タイプ A const&amp; の暗黙のオブジェクトパラメータにバインドされ、そのオブジェクトはここでは、 A const * タイプの this ポインターが指します。重要なのは、このポインターが実際に存在している間に、暗黙的なオブジェクトパラメーターは、メンバー関数を呼び出すためのルールがどのように構成されているか(およびコンストラクターに含まれない)を形式化するための理論的な構成にすぎないことです。 this はポインターです。これは、 this が導入されたとき、C ++にはまだ参照がなかったためです。

これが問題の理解に役立つことを願っています。

メンバー関数ポインターに関する優れた記事は、CodeProjectのメンバー関数ポインターと最速のC ++です。デリゲート。この記事では、単純なケースのメンバー関数ポインターについて、複数の継承を持つ仮想メンバー関数ポインターについて説明します。ボーナスとして、それは本当に役立つデリゲートの実装を提供します。

はい、関数へのポインターとメンバーへのポインターはまったく別物です。メンバーへのポインターには、-&gt; * または。* 演算子を使用して間接参照するオブジェクトインスタンスを指定する必要があります。メンバーへのポインターを使用するときに this が決定されるため、メンバーへのポインターを作成するときに使用される this パラメーターはありません(- &gt; * または。* )。

メンバーへのポインター関数とメンバーへのポインター変数の違いは、メンバーへのポインター関数と通常の関数ポインターの違いよりもおそらく少ないことに注意してください。

通常、メンバー関数と通常の関数はまったく異なる呼び出し規約を持つことができるため、それらの間でキャストすることはできません。

メンバー関数へのポインタのサイズは、異なるコンパイラを使用すると異なる場合があることに注意してください。

The Old Newモノのブログ

  

のサイズ   メンバ関数へのポインタは変更できます   クラスによって異なります。

これらは明確に異なるタイプであり、ユーザーが行う仮定はプラットフォーム/コンパイラ固有のものです。

このページには、メンバー関数ポイントの実装に関する詳細情報があります。多数の一般的なコンパイラの実装の詳細など、知りたいと思っていました。

すべての質問に答えるには: はい、それらは通常のポインターとは異なる特別なポインターです。 はい、boost :: functionはそれらを認識します。

標準では、呼び出しスタックの内部の詳細については何も言及されていません。実際、多くのコンパイラーは、実際の引数リストに応じて、整数レジスター、浮動小数点レジスター、および/またはスタックを使用する場合があります。 「this」ポインターは、もう1つの特別なケースです。

Boost :: functionは、内部で2つのコードパスを使用してこれを解決します。これは、2つのケースのコールスタックを調べることで確認できます。 boost :: functionがメンバー関数へのポインターを格納している場合、operator()は引数リストを分割します。最初の引数は、残りの引数とともにメンバー関数が呼び出されるオブジェクトとして使用されます。

他のすべての人の答えを補うために、Boost.Functionは、メンバー関数ポインターに代入演算子を特化することによって機能し、ユーザーがポインター演算子を渡したことを検出できるようにします。その関数を呼び出すと、メンバー関数ポインター((obj-&gt; * fun)(args))を呼び出す適切なメソッドに内部的に再解釈されます。

このリンクは非常に興味深いと思うかもしれません:

http://www.parashift.com/c++ -faq-lite / pointers-to-members.html

これは、メンバーへのポインタについて知りたいことすべての非常に良い説明です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top