如何访问类的静态成员?

40
我正在学习C++和Qt,但有时从书上复制的最简单的代码会出现错误。
我在Ubuntu 10.04上使用QtCreator IDE和g++4.4.2。 g++编译器语法与其他编译器有区别吗?例如,当我尝试访问静态成员时,总是出现问题。
#include <iostream>
using namespace std;
class A
{
   public:
      static int x;
      static int getX() {return x;}
};
int main()
{
   int A::x = 100; // error: invalid use of qualified-name 'A::x'
   cout<<A::getX(); // error: : undefined reference to 'A::x'
   return 0;
}

我认为这与声明中的herehere完全相同(不是吗?)。那么上面的代码有什么问题呢?

9个回答

58

您已经声明了静态成员,但是没有定义它们的位置。

基本上,您说了“存在某些静态成员”,但从未为其分配内存,您需要:

int A::x = 100;

在类的外部且不在主函数内。


1
这不是一个声明吗:static int getX(){return x;}? - sorush-r
1
在这种情况下,它同时声明和定义了getX()函数。如果没有{return x;},它只会是一个声明。而定义则是“使其工作的那一部分”,即实现或某些实际存储。 - Flexo

14

第 [9.4.2] 节

静态数据成员

在类定义中声明静态数据成员不算是定义,可以是未完成类型而非cv限定的void。静态数据成员必须在封装该成员的类定义所在的命名空间作用域内进行定义。在命名空间作用域的定义中,该静态数据成员的名称必须使用类名和::运算符进行限定。


11

由于静态成员变量既需要声明又需要定义,所以您需要在类外部定义该类的静态成员变量。

#include <iostream>
using namespace std;
class A
{
   public:
      static int x;
      static int getX() {return x;}
};

int A::x;         // STATIC MEMBER VARIABLE x DEFINITION

int main()
{
   A::x = 100;    // REMOVE int FROM HERE
   cout<<A::getX();
   return 0;
}

1
为什么我们需要 int A::x;?C++ 真的很丑。 - canbax

9

尝试:

#include <iostream>
using namespace std;
class A
{
   public:
      // This declares it.
      static int x;
      static int getX(){return x;}
};

// Now you need an create the object so
// This must be done in once source file (at file scope level)
int A::x = 100;


int main()
{
   A::x = 200;
   // Notice no 'int' keyword before A::x on this line. You can modify A::x

   cout<<A::getX(); // Should work
   return 0;
}

好的。它工作了。但对于模板类,会给出错误:template参数列表太少。(我写的是int SP <int> :: free = 100;) - sorush-r
1
@Sorush Rabiee:抱歉,我不是通灵者。您需要展示一些代码来说明问题。 - Martin York

3

试试这个例子:

#include<iostream>
using namespace std;

class check
{
        static int a;
    public:
        void change();
} ;
int check::a=10;
void check::change()
{
    a++;
    cout<<a<<"\n";
}

int main()
{

    int i,j;
    check c;
    check b;
    c.change();
    b.change();
    return 0;
}

1
为什么我们不能只写check::a = 10;(没有“int”说明符)?我的意思是,check::a已经声明为int。 - Maksim Gayduk
定义类外的非const静态变量的语法是“返回类型 类名::静态变量名=初始化”。如果我们省略了返回类型,编译器会抛出语法错误。同样适用于在类外定义成员函数。 - Eswaran Pandi

3

自从C++17版本起,您可以在static成员前面使用inline关键字,避免在类范围之外进行定义。现在您的代码应该是这样的:

#include <iostream>
using namespace std;
class A
{
   public:
      inline static int x;
      static int getX() {return x;}
};
int main()
{
   A::x = 100;    //Works now
   cout<<A::getX()<<'\n';
   return 0;
}

3
静态成员变量的定义必须在文件范围内,即在所有函数之外等地方。

1

现在你已经学会了如何使用静态类成员,我建议你只在以下情况下使用它们:

  • 用于模板。因此,在您的示例中,您可以在不同的类中拥有GetX(),并且在某个模板中使用:

    template< typename T >
    int func()
    {
        return T::GetX();
    }
    

    显然更加复杂。但是在这里,您的静态函数位于一个类中具有目的性。

  • 当函数需要访问类,即私有成员时。您可以将其设置为友元,但最好将其设置为静态。回调函数通常是这种情况。

其余时间,您可能会使用编译单元级别的函数和变量,这具有将成员从头文件中移除的优点(特别是如果它们是私有的)。给出的实现细节越少,越好。


0

情况1:静态变量

众所周知,在类内定义静态变量会导致编译错误。例如下面的代码:

class Stats
{
  public: 
     static int AtkStats[3];
     *static int a =20;*        // Error: defining a value for static variable
};

int Stats::AtkStats[3] =  {10, 0, 0};

输出:

error: ISO C++ forbids in-class initialization of non-const static member 'Stats::a'

案例2:const静态变量 对于const静态变量,我们可以在类内或类外定义一个值。
class Stats
{
  public: 
     static const int AtkStats[3];
     static const int a =20;        // Success: defining a value for a const static
};

const int Stats::AtkStats[3] =  {10, 0, 0};

const int Stats::a = 20;        // we can define outside also

输出:

Compilation success.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接