只调用其他类成员的类成员?

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 类,用于管理套接字/管道,因此我认为任何类型的继承都不会很顺利。

注意:如果这是一个可以通过谷歌搜到的问题,请让我知道,因为我不知道该如何搜索。


看一下反汇编,它可以内联。 - Luchian Grigore
3
请修复此帖子的格式,通过适当缩进所有内容。不要使用制表符。读起来很累人。 - Kerrek SB
@user1204406:我通常在网页中使用三个空格进行缩进。 - David Rodríguez - dribeas
3个回答

1
实际上,B.func() 做了更微妙的事情:
它不调用 A::func 而是 GlobalA.func(),GlobalA 是类 A 的一个实例。
因此,在这里,GlobalA 是一个单例(但以非常“原始”的方式表示为单个全局实例)。
所以,无论您创建多少个 B 实例,它们始终会调用同一个 A 实例(GlobalA)。

我不明白那怎么回答了这个问题。 - Lauer
我回答了这个问题,通过发现分析中的一些错误来解决这个问题。B::func不会调用A::func,而是GlobalA.func,这是一个非常大的差别,应该能够帮助您完善分析。 - dweeves

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来确保它在每种情况下都保持在同一个翻译单元中,从而实现相同的效果,这样可以让您在头文件中指定它们。
故事的寓意是不要为微小的细节而苦恼 - 编写有意义且易于维护的代码才是远远更重要的。

当然,这取决于编译器。虽然我认为可以肯定地说,在这种微不足道的情况下,任何像样的编译器都会进行内联处理。 - log0

0
这是一个常见的模式:即 桥接。 根据我的经验,它总是内联的(至少从 g++ 版本 4.3 开始)。
请参阅 Flexo 的答案,您发布的示例代码中对 A 成员函数的调用确实是内联的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接