C++知识点-静态成员变量和静态成员函数

静态成员变量

这里先引用GeeksforGeeks的一段内容:

Static data members are class members that are declared using static keywords. A static member has certain special characteristics. These are:

  • Only one copy of that member is created for the entire class and is shared by all the objects of that class, no matter how many objects are created.
  • It is initialized before any object of this class is being created, even before main starts.
  • It is visible only within the class, but its lifetime is the entire program

语法: static data_type data_member_name;

静态变量在任何类对象创建前初始化

我们看代码示例,一码胜千言

#include <iostream>

using namespace std;

class A {
public:
    A() {
        cout << "A constructed" << endl;
    }
};

class B {
    static A a;
public:
    B() {
        cout << "B constructed" << endl;
    }
};

int main() {
    B b;
    return 0;
}

// output
B constructed

我们看到B类有一个静态成员A类,但是在创建B的对象时并没有调用A的构造函数,原因很简单,即在类B中仅仅声明(declare)了静态类A,但没有在类外定义(define)它。 如果我们在静态成员变量定义前使用它,那么会编译报错,这和代码块中的静态变量不同,代码块中的静态变量会有常量初始化的过程,代码示例如下。

#include <iostream>

using namespace std;

class A {
public:
    int x;
    A() {
        cout << "A constructed" << endl;
    }
};

class B {
    static A a;
public:
    B() {
        cout << "B constructed" << endl;
    }
    static A getA() {return a;}
};

int main() {
    B b;
    // A a = b.getA(); // ERROR Compiler Error: undefined reference to `B::a' 
    static int n;
    cout << n << endl; // ok 0
    return 0;
}

定义静态成员变量

我们在类内定义静态成员变量时需要 static,在类外定义镜头成员变量时不用 static,语法如下。

class X { static int n; }; // declaration (uses 'static')
int X::n = 1;              // definition (does not use 'static')

这里需要注意几点:

  • const静态成员变量无法在类内初始化
  • 静态成员变量只能在方法外定义,且一定要定义完才能对起引用。

我们考虑下为什么不能在声明中初始化静态变量,这是因为声明描述来如何分配内存,但不分配内存。这里我们还是使用上面代码的例子来说明。

using namespace std;

class A {
public:
    int x;

    A() { cout << "A's constructor called " << endl; }
};

class B {
    static A a;
public:
    B() { cout << "B's constructor called " << endl; }

    static A getA() { return a; }
};

A B::a; // definition of a
int main() {
    B b1, b2, b3;
    A a = b1.getA();
    cout << a.x << endl; // 0
    return 0;
}

output

A's constructor called 
B's constructor called 
B's constructor called 
B's constructor called 
0

从上述结果我们也可以看出来静态成员变量确实在创建类对象之前初始化。

使用静态成员变量

有两种方法可以引用静态成员变量,<类对象名>.<静态数据成员名><类类型名>::<静态数据成员名>

To refer to a static member m of class T, two forms may be used: qualified name T::m or member access expression E.m or E->m, where E is an expression that evaluates to T or T* respectively. When in the same class scope, the qualification is unnecessary:

struct X
{
    static void f(); // declaration
    static int n;    // declaration
};
 
X g() { return X(); } // some function returning X
 
void f()
{
    X::f();  // X::f is a qualified name of static member function
    g().f(); // g().f is member access expression referring to a static member function
}
 
int X::n = 7; // definition
 
void X::f() // definition 
{ 
    n = 1; // X::n is accessible as just n in this scope
}

类对象共享静态成员

静态类成员有一个特点:无论创建了多少个对象,程序都只创建一个静态类变量副本。也就是说,类的所有对象共享同一个静态成员。静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
在这里插入图片描述
接下来看另一个代码示例

#include <iostream>

using namespace std;
class A {
public:
    static int x;
    int y;
    static void f() {
        // y++; Error invalid use of member 'y' in static member function
        x++;
        cout << "A static function, x = " << x << endl;
    }
};

int A::x;
int main() {
    A a;
    cout << "x = " << A::x << endl;
    cout << "x = " << a.x << endl;
    A::f();
    a.f();
    return 0;
}

output

x = 0
x = 0
A static function, x = 1
A static function, x = 2

const constexpr

C++提供了多种在类中定义常量的方式,其中比较常用的有 constconstexprenum

class X
{
	// method1 const
    const static int n = 1;
    const static int m{2}; // since C++11
    const static int k; // ok
    // method2 enum
    enum {Month=12};
    // method3 constexpr
    constexpr static int arr[] = { 1, 2, 3 };        // OK
    constexpr static std::complex<double> n = {1,2}; // OK
    constexpr static int k; // Error: constexpr static requires an initializer
};
const int X::k = 3;

其中注意:

  1. 使用 enum 时并不会创建数据成员,即所有的对象中都不包括枚举,另外Month知识一个符号名称,在作用于为整个类的代码中遇到它是,编译器将用12来替代它。而且只能是整数。
  2. 使用 constexpr 来创建类常量时,一定要给其定义,不能只是声明,而const可以只是声明,不用给出定义。

静态成员函数

#include <iostream>

using namespace std;

class Person {
public:
    Person() {};
    Person(char *name, int age);
    void show();
    static int getTotal();
private:
    static int m_total;
    char *m_name;
    int m_age;
};

Person::Person(char *name, int age) : m_name(name), m_age(age) {
    m_total++;
}

void Person::show() {
    cout << m_name << "的年龄是" << m_age << ", 总人数是" << m_total << endl;
}

int Person::getTotal() {
    return m_total;
}

// 一定要先初始化
int Person::m_total = 0;

int main() {
    Person *p1 = new Person("Alice", 18);
    Person *p2 = new Person("Bob", 18);
    p1->show();
    p2->show();
    int total1 = Person::getTotal();
    int total2 = p1->getTotal();
    cout << "total1 = " << total1 << ", total2 = " << total2 << endl;
    return 0;
}

静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
这里要注意的是普通的成员函数也能访问静态成员变量。这一点上和Java中的static用法很像。

Reference

  1. static members
  2. C++ static静态成员变量
  3. C++静态成员变量和静态成员函数
  4. Static data members in C++
  5. C++ static静态成员函数
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值