对静态类成员的未定义引用
任何人都可以解释为什么下面的代码不会编译 至less在g ++ 4.2.4上。
而更有趣的是,为什么在我将MEMBER转换为int时会编译?
#include <vector> class Foo { public: static const int MEMBER = 1; }; int main(){ vector<int> v; v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER' v.push_back( (int) Foo::MEMBER ); // OK return 0; }
您需要实际定义静态成员(在类定义之后)。 尝试这个:
class Foo { /* ... */ }; const int Foo::MEMBER; int main() { /* ... */ }
这应该摆脱未定义的参考。
问题来自于新的C ++特性的一个有趣的冲突,以及你正在尝试做什么。 首先,我们来看一下push_back
签名:
void push_back(const T&)
期待对T
型对象的引用。 在旧的初始化系统下,存在这样一个成员。 例如,下面的代码编译得很好:
#include <vector> class Foo { public: static const int MEMBER; }; const int Foo::MEMBER = 1; int main(){ std::vector<int> v; v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER' v.push_back( (int) Foo::MEMBER ); // OK return 0; }
这是因为有一个实际的对象存储在那个值中。 但是,如果您切换到指定静态const成员的新方法(如上所述), Foo::MEMBER
不再是一个对象。 这是一个常数,有点类似于:
#define MEMBER 1
但是没有预处理器macros的头痛(并且具有types安全性)。 这意味着期待参考的vector不能得到一个。
如果需要定义,C ++标准需要为你的静态const成员定义。
定义是必需的,例如,如果使用地址。 push_back
通过const引用接受其参数,因此编译器需要使用成员的地址,并且需要在名称空间中定义它。
当你明确地转换常量时,你正在创build一个临时的,这是临时的,这是绑定到参考(在标准的特殊规则下)。
这是一个非常有趣的案例,我认为这是值得提出的问题,以便std被更改为对于常量成员具有相同的行为!
虽然以一种奇怪的方式,这可以被看作是一元运算符“+”的合法使用。 基本上, unary +
的结果是一个右值,所以适用于rvalue绑定到const引用的规则,我们不使用我们的静态const成员的地址:
v.push_back( +Foo::MEMBER );
Aaa.h
class Aaa { protected: static Aaa *defaultAaa; };
Aaa.cpp
// You must define an actual variable in your program for the static members of the classes static Aaa *Aaa::defaultAaa;
不知道为什么演员工作,但Foo :: MEMBER不分配,直到第一次加载Foo,因为你永远不会加载,它永远不会被分配。 如果你在某个地方有一个Foo的参考,它可能会工作。
使用C ++ 11,以上对于基本types是可能的
class Foo { public: static constexpr int MEMBER = 1; };
constexpr
部分创build了一个静态expression式 ,而不是一个静态variables – 这就像一个非常简单的内联方法定义一样。 尽pipe如此,这个方法在模板类中用Cstring表示,有点不稳定。
关于第二个问题:push_ref作为一个参数引用,你不能有一个类/结构的静态常量的引用。 一旦你调用static_cast,就会创build一个临时variables。 并且可以传递这个对象的引用,一切正常。
或者至less我的同事谁解决这个如此说。