2011-06-14 43 views
0

在类中使用静态类成员是常见操作。考虑以下定义:使用正在定义的类的静态类成员

foo.h中

class foo 
    { 
    public: 
     virtual ~foo(); 
    protected: 
     foo(); 
     static foo ms_oFooStaticObject; 
    } 

Foo.cpp中

foo foo::ms_oFooStaticObject; 
    foo::foo(){} 
    foo::~foo(){} 
    void main() 
    { 
     int i; 
    } 

在编译上面的代码没有编译器错误,你可以简单的步骤模式下运行,并观察静态C-tor正在执行。

这怎么可能?这是一个编译器错误?

我使用Visual Studio 2005(专业版)与SP1(SP.050727-7600)

+3

当面对一个“奇怪”的行为时,假设编译器有一个bug是你应该做的最后一件事**。您对您提供的代码有何期望? – ereOn 2011-06-14 09:23:13

+0

附注:不要使用'void main'。 – 2011-06-14 09:45:24

回答

1

@ user797308:我想你也没问题,如果有人声明和定义一个名为ms_oFooStaticObject全局变量。换句话说,而不是定义foo foo::ms_oFooStaticObject;定义foo ms_oFooStaticObject;(这将需要构造函数是公开的,当然)。

普通老香草全局变量通过extern <type> <global_name>;声明并使用<type> <global_name>;(可能有一些初始值)定义。

类中的那些静态成员实际上只是全局变量,类名前加上了它们的名称。类定义正在声明它们。想想类foo中ms_oFooStaticObject的声明与extern foo ms_oFooStaticObject;类似。如何定义变量?这就是foo foo::ms_oFooStaticObject;声明正在做的事情。

与globals的比较很适合。有很多与全局相关的行李。将类的静态成员想象为具有与全局变量相同类型的问题是一个好主意。

编辑

谢里夫的回应引发了思考。 user797308的问题可能是foo::ms_oFooStaticObject本身受到保护,那么它如何在文件范围内定义呢?答案是,因为语言要求在文件范围内定义这些静态数据成员,所以语言当然必须允许这样的定义,即使对于具有非公开可见性的静态成员也是如此。

+0

非常感谢。这对我来说确实是一个亮点,它解释了使用情况。 – NirMH 2011-06-14 11:28:37

4

这不是一个编译器错误 - 建设类的静态情况下被定义不会触发递归建设(作为非foo类型的静态成员会这样做),所以它非常好。

ms_oFooStaticObject的定义(在Foo.cpp中)的点,foo是一个完整的类型,它的构造,虽然protected,是ms_oFooStaticObject访问。

foo foo::ms_oFooStaticObject; 

要调用的class foo对象:

0

构造foo::foo()是因为你在Foo.cpp中的文件做了static变量定义执行。

0

让我猜。我想你想知道因为fooprotected,所以你认为下面这行必须给出错误,因为它试图从外部调用非公共构造函数。

foo foo::ms_oFooStaticObject; //definition lies outside the class 

好吧,那是不正确的。 ms_oFooStaticObject不是一个全球性的对象,尽管起初似乎是它是,看到它在班级之外的定义。

事实是,ms_oFooStaticObject仍然类的成员,即使其定义是在类之外。而像任何成员,它可以访问不仅protected的成员,它可以访问甚至private的:

class A 
{ 
    A() { cout << "constructed" << endl; } //private constructor 
    static A a;        
}; 

A A::a; //okay - member has access to private constructor! 
A b;  //error - non-member doesn't has access to private constructtor 

编译并看到错误消息,行号:http://www.ideone.com/qocH0

顺便说一句,你的main()是非标准的,它应该是其中之一:

int main(); 
int main(int argc, char *argv[]);