Search code examples
c++shared-librarieslinkage

External or internal linkage for static class member functions?


I believe a C++ member function declared as static has internal linkage. When I compile libbar.cpp/libbar.hpp (below) as a shared object, I find that I can call both test1 and test2 from a separate (main) program. Why is the static member function test2 available outside of its translation unit?

// 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__; }

I compile the shared object with $CXX libbar.cpp -shared -fpic -o libbar.so and the main program (below) using $CXX -I bar -L bar main.cpp -Wl,-rpath,$PWD/bar -lbar. I am using GCC and Clang on Debian.

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

Solution

  • The static keyword has different meanings in different contexts.

    • At file scope and namespace scope, it means the function or variable declared as static has internal linkage.
    • At class scope it means that the function or data member is not associated with an object of that class. This implies that you can call the test2 function like this: Foo::test2().
    • At function scope it means that the variable declared static is independent of the current invokation of the function and will be initialized only once. The following function will always return the number N the N'th time it is called.
    int counter() {  
        static int count = 0;
        return ++count;
    }
    

    About member functions with internal linkage:

    In C++, as opposed to C, types also have linkage. Member functions of a class have the same linkage as the class itself. So to have a member function with internal linkage you have to declare the class within an anonymous namespace:

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

    Now the class Foo has internal linkage and thus Foo::test() also has internal linkage and won't be available outside of the translation unit.