C++ 对静态类成员的未定义引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/272900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Undefined reference to static class member
提问by Pawel Piatkowski
Can anyone explain why following code won't compile? At least on g++ 4.2.4.
谁能解释为什么下面的代码不能编译?至少在 g++ 4.2.4 上。
And more interesting, why it will compile when I cast MEMBER to int?
更有趣的是,为什么当我将 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;
}
采纳答案by Drew Hall
You need to actually define the static member somewhere (after the class definition). Try this:
您需要在某处(在类定义之后)实际定义静态成员。尝试这个:
class Foo { /* ... */ };
const int Foo::MEMBER;
int main() { /* ... */ }
That should get rid of the undefined reference.
那应该摆脱未定义的引用。
回答by Douglas Mayle
The problem comes because of an interesting clash of new C++ features and what you're trying to do. First, let's take a look at the push_back
signature:
问题出现是因为新的 C++ 特性与您正在尝试做的事情之间发生了有趣的冲突。首先,让我们看一下push_back
签名:
void push_back(const T&)
It's expecting a reference to an object of type T
. Under the old system of initialization, such a member exists. For example, the following code compiles just fine:
它期待对类型为 的对象的引用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;
}
This is because there is an actual object somewhere that has that value stored in it. If, however, you switch to the new method of specifying static const members, like you have above, Foo::MEMBER
is no longer an object. It is a constant, somewhat akin to:
这是因为某处有一个实际对象存储了该值。但是,如果您切换到指定静态常量成员的新方法,就像上面那样,Foo::MEMBER
则不再是对象。它是一个常数,有点类似于:
#define MEMBER 1
But without the headaches of a preprocessor macro (and with type safety). That means that the vector, which is expecting a reference, can't get one.
但是没有预处理器宏的麻烦(并且具有类型安全性)。这意味着需要引用的向量无法获得引用。
回答by Richard Corden
The C++ standard requires a definition for your static const member if the definition is somehow needed.
如果以某种方式需要定义,C++ 标准需要为您的静态常量成员定义。
The definition is required, for example if it's address is used. push_back
takes its parameter by const reference, and so strictly the compiler needs the address of your member and you need to define it in the namespace.
定义是必需的,例如,如果使用它的地址。 push_back
通过 const 引用获取其参数,因此编译器需要您的成员地址,因此您需要在命名空间中定义它。
When you explicitly cast the constant, you're creating a temporary and it's this temporary which is bound to the reference (under special rules in the standard).
当您显式转换常量时,您正在创建一个临时对象,并且这个临时对象绑定到引用(根据标准中的特殊规则)。
This is a really interesting case, and I actually think it's worth raising an issue so that the std be changed to have the same behaviour for your constant member!
这是一个非常有趣的案例,我实际上认为值得提出一个问题,以便将 std 更改为您的常量成员具有相同的行为!
Although, in a weird kind of way this could be seen as a legitimate use of the unary '+' operator. Basically the result of the unary +
is an rvalue and so the rules for binding of rvalues to const references apply and we don't use the address of our static const member:
虽然,以一种奇怪的方式,这可以被视为一元“+”运算符的合法使用。基本上,结果unary +
是一个右值,因此将右值绑定到常量引用的规则适用,我们不使用静态常量成员的地址:
v.push_back( +Foo::MEMBER );
回答by iso9660
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;
回答by starturtle
With C++11, the above would be possible for basic types as
使用 C++11,上述对于基本类型是可能的
class Foo {
public:
static constexpr int MEMBER = 1;
};
The constexpr
part creates a static expressionas opposed to a static variable- and that behaves just like an extremely simple inline method definition. The approach proved a bit wobbly with C-string constexprs inside template classes, though.
该constexpr
部分创建了一个静态表达式而不是静态变量——它的行为就像一个非常简单的内联方法定义。不过,在模板类中使用 C 字符串 constexprs 的方法证明有点不稳定。
回答by Paul Tomblin
No idea why the cast works, but Foo::MEMBER isn't allocated until the first time Foo is loaded, and since you're never loading it, it's never allocated. If you had a reference to a Foo somewhere, it would probably work.
不知道为什么强制转换有效,但是直到第一次加载 Foo 才会分配 Foo::MEMBER ,并且由于您从未加载它,因此从未分配过它。如果您在某处引用了 Foo,它可能会起作用。
回答by Quarra
Regarding the second question: push_ref takes reference as a parameter, and you cannot have a reference to static const memeber of a class/struct. Once you call static_cast, a temporary variable is created. And a reference to this object can be passed, everything works just fine.
关于第二个问题:push_ref 将引用作为参数,并且您不能引用类/结构的静态常量成员。一旦您调用 static_cast,就会创建一个临时变量。并且可以传递对该对象的引用,一切正常。
Or at least my colleague who resolved this said so.
或者至少我解决这个问题的同事是这么说的。