首页 文章

对静态成员进行未定义的引用意味着什么?

提问于
浏览
18

我刚刚写了一个包含一些静态数据成员的类,但现在我收到有关“未定义引用”的错误 . 为什么这不起作用?我究竟做错了什么?

(注意:这是Stack Overflow的C FAQ的一个条目 . 如果你想批评在这个表单中提供常见问题解答的想法,那么发布所有这些的meta上的帖子就是这样做的地方 . 这个问题在C聊天室中受到监控,其中FAQ的想法首先出现在那里,所以你的答案很可能被那些提出这个想法的人阅读 . )

2 回答

  • 26

    要理解这一点,你应该很好地理解compiling and linking,以及declarations and definitions之间的区别 .


    考虑以下课程:

    //In header file
    class Example {
        static bool exampleStaticMember;
    };
    

    这里, exampleStaticMember 已声明但未定义 . 这意味着如果 exampleStaticMember 的使用方式意味着它必须具有地址,那么必须有一个单独的定义 . 通常,类定义中的静态数据成员的声明不是该成员的定义 .

    所需的声明通常放在cpp文件中,该文件包含该类成员的其他定义 . 它必须与类定义位于同一名称空间中 . 该定义通常如下所示:

    //In source file:
    //This may optionally have an initialiser (eg "= true")
    bool Example::exampleStaticMember;
    

    该定义可以放在任何cpp文件中,但不应该放在带有类的头文件中,因为这可能会破坏One Definition Rule .

    作为一种特殊情况,如果静态成员变量是const整数或枚举类型,那么它可以在类定义中具有初始化:

    //In header file
    class Example {
        static const int initialised = 15;
    };
    

    在这种情况下,仍然需要cpp文件中的定义,但不允许使用初始化器:

    //In source file
    //Note: no initialiser!
    const int Example::initialised;
    

    已经初始化的静态成员可以在常量表达式中使用 .

    Templates

    对于模板的静态数据成员,情况略有不同 . 应该在 Headers 中定义静态成员以及类的其余部分:

    //In header file
    template<typename T>
    class Example {
        static int exampleInt;
        static T exampleT;
    }
    template<typename T> int Example<T>::exampleInt;
    template<typename T> T Example<T>::exampleT;
    

    这是有效的,因为类模板的静态数据成员的One Definition Rule存在特定的例外 .

    Other uses of static

    static 关键字应用于不在类范围内的函数和对象时,它可以具有非常不同的含义 .

    当应用于函数作用域中的对象时,它声明一个在函数的第一次执行中初始化的对象,并随后在函数调用之间保持其值 .

    当应用于命名空间作用域(在任何类或函数定义之外)的对象或函数时,它使用internal linkage声明对象或函数 . 对于对象,不推荐使用此用法,因为unnamed-namespace提供了更好的替代方法 .

  • 5

    您必须实例化.cpp文件中标头中定义的静态成员 . 例如:

    // foo.h
    
    class foo {
        static int X;
    };
    
    
    // foo.cpp
    
    #include "foo.h"
    
    int foo::X = 0;
    

相关问题