g ++签名/符号:静态和非静态成员函数之间没有区别?

时间:2014-04-25 14:49:23

标签: c++ g++

两个以不同方式定义相同类 A 的库(这是遗留垃圾代码)

A的原型:

lib中的

#include <string>

struct A
{
     static void func( const std::string& value);
};
lib B中的

#include <string>

struct A
{
   void func( const std::string& value);
};

main.cpp使用lib A中的 A :s标头(组件A)

#include "liba.h"

int main()
{
    A::func( "some stuff");
    return 0;
}

main与lib A和lib B都链接。

如果lib B是&#34;在&#34之前链接; lib A(在link-directive中)我们得到一个核心,因此,lib B:s定义是纠察队。

这不是我预期的行为。我认为符号之间会有一些区别,因此加载器/运行时链接器可以选择正确的符号。也就是说,非静态成员函数的隐藏this指针以某种方式包含在符号中。

这是否真的符合行为?

两者都有相同的行为:

g ++(GCC)4.4.7 20120313(Red Hat 4.4.7-4)

RHEL devtool with g ++ 4.8.1

3 个答案:

答案 0 :(得分:3)

无法使用静态成员函数重载非静态成员函数,反之亦然。从标准:

  

ISO 14882:2003 C ++标准13.1 / 2 - 可重载声明

     

某些函数声明不能   超载:

     
      
  • 只能在返回类型上有所不同的函数声明不能​​重载。
  •   
  • 如果其中任何一个是static成员函数声明(9.4),则不能重载具有相同名称和相同参数类型的成员函数声明。
  •   

可能会在问题5365714中找到更多详细信息和参考资料。

所以你在同一个程序中有两个相同类A的定义,它们应该是相同的,而它们不是。 要在单独的翻译单元中存在不一致的定义时发出错误信号对于链接器不是必需的结果是实现定义程序格式不正确(根据@ jonathan的评论更新)。在C++ faq中来自Stroustrup的说明示例中,它被描述为未定义的行为。

对于GCC,正如您所说,使用的定义取决于链接命令中库的顺序(假设lib A和lib B是自己编译的,然后与主程序链接)。链接器使用从左到右传递的库中的第一个定义。 关于GCC的链接顺序选项的讨论在409470

答案 1 :(得分:1)

你不能基于返回类型重载C ++中的函数,所以我猜你不能在静态/ v非静态成员函数的基础上进行。

您需要修复其中一个头文件 - 最好不要两次声明相同的类型。

为了说明一下这个;

struct A {
    int X(int b);
};
int A::X(int b)
{
    return b+8;
}

$ g++ x.cc -c
$ nm x.o
0000000000000000 T _ZN1A1XEi

并将其与此进行比较....

struct A {
    static int X(int b);
};
int A::X(int b)
{
    return b+8;
}

$ g++ x.cc -c
$ nm x.o
0000000000000000 T _ZN1A1XEi

观察两件事;

  1. 当我宣布A :: X的实际实现时,我没有指定它是一个静态成员函数 - 编译器并不关心,而是从struct的定义中获取了所有信息。
  2. 符号的名称重整,无论是否为静态,都是相同的_ZN1A1XEi,它将类的名称编码为方法的名称和参数的类型。
  3. 总而言之,对编译代码使用不正确的标头会导致未定义的行为....

答案 2 :(得分:0)

由于类不能同时具有静态成员函数和具有相同名称的非静态成员函数,因此不需要在受损名称中包含该信息。

您需要通过为类包含命名空间,重命名它们或小心不要同时使用这些库来解决此问题。