Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Namespace and static class members linking

Tags:

c++

gcc

g++

linker

Lets say I have two files:

/**
 * class.cpp
 */ 
#include <stdio.h>
class foo 
{
private:
        int func();
};

int foo::func(void)
{
        printf("[%s:%d]: %s\n", __FILE__, __LINE__, __FUNCTION__);
        return -1; 
}

and

/**
 * main.cpp
 */ 
#include <stdio.h>
namespace foo 
{
        int func(void);
}
int main(void)
{
        int ret = foo::func();
        printf("[%s:%d]: ret=%d\n", __FILE__, __LINE__, ret);
        return 0;
}

compiled as follows:

g++ -o a.out main.cpp class.cpp 

There is an output from executable file:

[class.cpp:15]: func
[main.cpp:14]: ret=-1

And finally my question:

Why is this sample code compiled without any errors and we are able to invoke private method of class foo ?

Compiled with gcc 4.6.3 but not only. I know that the compiler does not distinguish those two symbols (func function from namespace foo and private function foo from class foo). Output from nm:

nm class.o
00000000 T _ZN3foo4funcEv
00000017 r _ZZN3foo4funcEvE12__FUNCTION__
         U printf

nm main.o
         U _ZN3foo4funcEv
00000000 T main
         U printf

I would like to ask whether this behavior is correct or not? IMHO this is not correct behavior and it is not safe at all (breaks down encapsulation).

I would like to mention that compiler from visual studio 2008 does not link those two symbols.

like image 599
pako Avatar asked Mar 20 '13 19:03

pako


People also ask

Can static member functions access private members?

DR; TL; Yes it can.

Why static members are defined outside the class?

As per OOPS guidelines compiler does not allocate memory to class instead of that it allocates memory to objects, but static members are independent of object, so to allocate memory to static variables, we define the static data members outside of the class, that's why once this variable is declared, it exists till the ...

Can we call static member function of a class using object of a class?

Static functions in a class: Just like the static data members or static variables inside the class, static member functions also does not depend on object of class. We are allowed to invoke a static member function using the object and the '.

Can a static member function access member variable of an object?

A static member function cannot access non-static member variable.


1 Answers

Why does the compiler not complain?

Note that "class", "struct" and "namespace" all define a namespace as far as the compiler is concerned. So the compiler decorates the symbols accordingly. It would complain if you define both the class and the namespace in the same file, however it is not the case here.

Why does the linker not complain?

The way you have written the code, leaves the func() defined in namespace foo weaker than the func() defined in class foo. Basically, the func() defined in namespace foo is just a signature without implementation. You can see that it is left to the linker to resolve the symbol at runtime because the implementation is not in main.cpp:

nm main.o
       U _ZN3foo4funcEv
//Here^^^^

This way, since the namespace and class names happened to be the same (resulting in same symbols for foo::func), linker solves the symbol at linktime, finds a strong definition with the same symbol, and links against it.

If you were to implement the func() in the namespace foo as well:

/**
 * main.cpp
 */
#include <stdio.h>

namespace foo
{
    int func(void) {
        printf("NM_FOO [%s:%d]: %s\n", __FILE__, __LINE__, __FUNCTION__);
        return -1;
    };
}
int main(void)
{
    int ret = foo::func();
    printf("[%s:%d]: ret=%d\n", __FILE__, __LINE__, ret);
    return 0;
}

You would have seen that the linker complains with:

duplicate symbol foo::func()     in:
/var/folders/.../class.o
/var/folders/.../main.o
ld: 1 duplicate symbol for architecture x86_64

If you look at the main.o this time you would see:

0000000000000064 T __ZN3foo4funcEv
0000000000000158 S __ZN3foo4funcEv.eh
00000000000000e0 s __ZZN3foo4funcEvE12__FUNCTION__
0000000000000000 T _main
0000000000000128 S _main.eh
                 U _printf

And class.o:

0000000000000000 T __ZN3foo4funcEv
00000000000000a0 S __ZN3foo4funcEv.eh
0000000000000080 s __ZZN3foo4funcEvE12__FUNCTION__
                 U _printf

both of which defines the same function symbol equally strong, resulting in the linker error.

Remember, the linker does not know about the difference between a namespace and a class. It resolves the symbols that are in the object code. It will only complain if strong re-definitions happen. One or multiple weaker definitions with one strong definition is perfectly fine in the linker world.

like image 91
meyumer Avatar answered Oct 22 '22 08:10

meyumer