3

与えられた:

#include <stdio.h>

class A
{
  friend class B;
 private:
  void func();
} GlobalA;

void A::func()
{
  printf("A::func()");
}

class B
{
 public:
  void func();
};

void B::func()
{
  GlobalA.func();
}

int main()
{
  B b;
  b.func();
  getchar();
}

だから本当にすべてB::func()は電話A::func()です、これを行うためのより良い方法はありますか?A::func()または、コンパイラはコンパイル時に直接呼び出すだけですか。

制約: class Aスレッドを作成し、他の複数のクラスで使用されます。ソケット/パイプを管理するためのグローバルIOクラスであるため、どのタイプの継承もうまくいくとは思いません。

注:これがグーグル可能な問題である場合、私は何を検索するかをしなかったので私に知らせてください。

4

3 に答える 3

1

実際、 B.func() はもっと微妙なことをします:

A::func を呼び出しませんが、GlobalA.func() を呼び出します。GlobalA はクラス A のインスタンスです。

したがって、ここで GlobalA はシングルトンです (ただし、単一のグローバル インスタンスの非常に「生の」方法で表現されます)。

したがって、作成する B インスタンスの数に関係なく、それらは常に同じ A インスタンス (GlobalA) を呼び出します。

于 2012-09-24T13:02:49.767 に答える
0

これは一般的なパターンです。つまり、bridgeです。私の経験から、それは常にインライン化されています (少なくともバージョン 4.3 以降の g++)。

Flexo の回答を参照してくださいA。メンバー関数の呼び出しは、投稿したサンプル コードで実際にインライン化されています。

于 2012-09-24T12:57:12.433 に答える
0

コンパイラから生成されたアセンブリを確認します (GCC 4.7 -O3 を使用しました)。

為にA::func()

_ZN1A4funcEv:
.LFB31:
    .cfi_startproc
    subl    $28, %esp
    .cfi_def_cfa_offset 32
    movl    $.LC0, 4(%esp)
    movl    $1, (%esp)
    call    __printf_chk
    addl    $28, %esp
    .cfi_def_cfa_offset 4
    ret
    .cfi_endproc

そしてB::func()

_ZN1B4funcEv:
.LFB32:
    .cfi_startproc
    subl    $28, %esp
    .cfi_def_cfa_offset 32
    movl    $.LC0, 4(%esp)
    movl    $1, (%esp)
    call    __printf_chk
    addl    $28, %esp
    .cfi_def_cfa_offset 4
    ret
    .cfi_endproc

それらは同じです - コンパイラは裏で無料で賢いことをしてくれます。この場合、あなたの例はすべて同じ翻訳単位にあったため、コンパイラがそのようにする価値があるかどうかを判断するのは簡単です。(ほとんどの場合、それが価値がない場合があり、コンパイラーは、特定のターゲットに最適なものを見つけ出すのに役立つかなり優れた一連のヒューリスティックを備えています)。

それらが異なる翻訳単位にある場合、それを行うのは非常に難しくなります。一部のコンパイラは引き続き同じ最適化を管理しますが、すべてではありません。inlineもちろん、これらの関数をヘッダー ファイルで指定できるように定義することで、すべてのケースで同じ翻訳単位内にとどまることを保証できます。

この話の教訓は、細部にまで気を取られないことです。理にかなっていて保守可能なコードを書くことは、はるかに重要です。

于 2012-09-24T13:02:42.277 に答える