亲宝软件园·资讯

展开

C++的静态成员变量和静态成员函数

EJoft 人气:0

静态成员变量

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

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

语法: 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')

这里需要注意几点:

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

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用法很像。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!      

加载全部内容

相关教程
猜你喜欢
用户评论