静态类成员函数的外部链接还是内部链接?

External or internal linkage for static class member functions?

提问人:user2023370 提问时间:7/28/2023 更新时间:7/28/2023 访问量:58

问:

我相信声明为 C++ 成员函数具有内部链接。当我将 libbar.cpp/libbar.hpp(如下)编译为共享对象时,我发现我可以同时调用两者并从单独的(主)程序调用。为什么静态成员函数在其转换单元之外可用?statictest1test2test2

// bar/libbar.hpp    
struct Foo
{
  void test1();
  static void test2();
};

// bar/libbar.cpp
#include <iostream>

void Bar::test1() { std::cout << __PRETTY_FUNCTION__; }
void Bar::test2() { std::cout << __PRETTY_FUNCTION__; }

我使用 和 程序(如下)编译共享对象。我在 Debian 上使用 GCC 和 Clang。$CXX libbar.cpp -shared -fpic -o libbar.somain$CXX -I bar -L bar main.cpp -Wl,-rpath,$PWD/bar -lbar

// main.cpp
#include "libbar.hpp"                                                            
                                                                                
int main(int argc, char *argv[])                                                 
{
  Bar b{};                                                                       
  b.test1();                                                                     
  b.test2();
  return 0;                                                                      
}
C++ 共享库 联动

评论

3赞 chrysante 7/28/2023
请看这个答案。基本上,关键字在不同的上下文中具有不同的含义。在文件范围和命名空间范围,它意味着内部链接,而在类范围,它意味着“此函数不接受对象参数”static
0赞 Petr Skocik 7/28/2023
从理论上讲,将一些非静态(如在实际对象绑定中)成员函数设置为静态(如在文件本地)可能是可取的,但我想 C++ 不允许这样做。奇怪的语言。
0赞 chrysante 7/28/2023
@PetrSkocik它确实允许它,看看我的答案
1赞 Petr Skocik 7/28/2023
@chrysante 如果你把整个类放在一个匿名命名空间中,这不会使每个成员函数(文件本地)都是静态的吗?理想情况下,您可以对单个函数放置或不放置该存储类属性。
2赞 chrysante 7/28/2023
@PetrSkocik 是的,类的每个成员函数都与类本身具有相同的链接。对于私有成员函数,这确实是语言的一个缺点,因为它们在二进制文件中总是不必要地可见。

答:

5赞 chrysante 7/28/2023 #1

关键字在不同的上下文中具有不同的含义。static

  • 在文件范围和命名空间范围,它表示声明为具有内部链接的函数或变量。static
  • 在类范围内,这意味着函数或数据成员不与该类的对象相关联。这意味着您可以像这样调用该函数: .test2Foo::test2()
  • 在函数作用域,这意味着声明的变量与函数的当前调用无关,并且只会初始化一次。以下函数在第 N 次调用时将始终返回数字 N。static
int counter() {  
    static int count = 0;
    return ++count;
}

关于具有内部链接的成员函数:

在 C++ 中,与 C 相反,类型也具有链接。类的成员函数与类本身具有相同的链接。因此,要使成员函数具有内部链接,您必须在匿名命名空间中声明该类:

namespace {
class Foo {
    void test();
};
void Foo::test() { /* ... */ }
}

现在,该类具有内部链接,因此也具有内部链接,并且在翻译单元之外不可用。FooFoo::test()

评论

0赞 user2023370 7/28/2023
谢谢。我认为静态数据成员也是如此。
1赞 chrysante 7/28/2023
@user2023370 是的,这同样适用于数据成员。