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 类,所以我不相信任何类型的继承都会顺利进行。

注意:如果这是一个 google-able 问题,请让我知道,因为我没有搜索什么。

4

3 回答 3

1

事实上 B.func() 做了一些更微妙的事情:

它不调用 A::func 而是调用 GlobalA.func() , GlobalA 是类 A 的一个实例。

所以这里 GlobalA 是一个单例(但以单个全局实例的非常“原始”的方式表示)

因此,无论您创建多少个 B 实例,它们都将始终调用同一个 A 实例 (GlobalA)。

于 2012-09-24T13:02:49.767 回答
0

这是一个常见的模式:即。根据我的经验,它总是内联的(至少从 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 回答