服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++的静态成员变量和静态成员函数你了解多少

C++的静态成员变量和静态成员函数你了解多少

2022-09-26 14:42EJoft C/C++

这篇文章主要为大家详细介绍了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;

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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)它。 如果我们在静态成员变量定义前使用它,那么会编译报错,这和代码块中的静态变量不同,代码块中的静态变量会有常量初始化的过程,代码示例如下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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,语法如下。

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

这里需要注意几点:

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

?
1
2
3
4
5
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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访问规则;

C++的静态成员变量和静态成员函数你了解多少

接下来看另一个代码示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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

?
1
2
3
4
x = 0
x = 0
A static function, x = 1
A static function, x = 2

const constexpr

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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可以只是声明,不用给出定义。

静态成员函数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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用法很像。

总结

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

原文链接:https://blog.csdn.net/EJoft/article/details/122926070

延伸 · 阅读

精彩推荐
  • C/C++C++ namespace案例详解

    C++ namespace案例详解

    这篇文章主要介绍了C++ namespace案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    福桐9282021-12-18
  • C/C++C语言进阶几分钟带你理解大小端存储模式

    C语言进阶几分钟带你理解大小端存储模式

    这篇文章主要为大家介绍了C语言进阶大小端模式的示例详解,带各位读者朋友五分钟脚踩大小端模式,有需要的朋友可以借鉴参考下,希望能够有所帮助...

    乔乔家的龙龙10122022-09-23
  • C/C++C语言 数据类型详细介绍

    C语言 数据类型详细介绍

    本文主要讲解C语言 数据类型,这里整理了详细的数据类型的资料,希望能帮助刚刚开始学习C语言的同学...

    C语言教程网6692021-04-13
  • C/C++C语言令人抓狂的一面-全局变量

    C语言令人抓狂的一面-全局变量

    作为一名程序员,如果说沉迷一门编程语言算作一种乐趣的话,那么与此同时反过来去黑一门编程语言就是这种乐趣的升华。今天我们就来黑一把C语言,好...

    C语言与C++编程5282022-04-12
  • C/C++C++ 流插入和流提取运算符的重载的实现

    C++ 流插入和流提取运算符的重载的实现

    这篇文章主要介绍了C++ 流插入和流提取运算符的重载的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    小林coding10252021-08-06
  • C/C++C语言实现扫雷游戏

    C语言实现扫雷游戏

    这篇文章主要为大家详细介绍了C语言实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    z向前12142021-08-10
  • C/C++C++ 中使用lambda代替 unique_ptr 的Deleter的方法

    C++ 中使用lambda代替 unique_ptr 的Deleter的方法

    这篇文章主要介绍了C++ 中使用lambda代替 unique_ptr 的Deleter的方法,需要的朋友可以参考下...

    C++教程网9202021-05-07
  • C/C++C++中共用体的定义与应用总结

    C++中共用体的定义与应用总结

    共同体的定义类似结构体,不过共同体的所有成员都在同一段内存中存放,起始地址一样,并且同一时刻只能使用其中的一个成员变量...

    C++教程网6622021-01-07