WHCSRL 技术网

从零开始的C++那些事儿(一)

项目介绍

这是笔者自己阅读C++那些事的过程中的笔记整理。该项目是一个适合初学者从入门到进阶的C++仓库。这里笔者和大家分享自己的阅读过程。希望大家在C++的学习过程中能够找到自己的乐趣。

static那些事

static关键字与不同的类型使用时,具有不太的含义。

静态变量

  1. 函数中的变量:当变量声明为static时,空间将在程序的生命周期内分配。即使多次调用该函数,静态变量的空间也只分配一次,前一次调用中的变量值通过下一次函数调用传递。可用于需要存储先前函数状态的场景。
#include <iostream> 
#include <string> 
using namespace std;

void func()
{
    // static variable 
    static int count = 0;
    cout << count << " ";

    // value is updated and 
    // will be carried to next 
    // function calls 
    count++;
}

int main()
{
    for (int i = 0; i < 5; i++)
        func();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

输出:

0 1 2 3 4
  • 1

上面程序中的变量count被声明为static。因此,它的值通过函数调用来传递。每次调用函数时,都不会对变量计数进行初始化。

  1. 类中的静态变量
    类中的静态变量由对象共享。对于不同的对象,都拥有相同的静态变量。因此,静态变量不能通过构造函数初始化。一般来说,可以在类的源文件中对静态函数进行初始化。
//Object.h
class Object
{
public:
	static int i;

	Object();
};
//Object.cpp
#include "Object.h"

int Object::i = 10;

Object::Object()
{
	
}
//main.cpp
#include <iostream>
#include "Object.h"
using namespace std;

int main()
{
    Object a;
	Object b;

	cout << a.i << " " << b.i << endl;
	a.i = 1;
	cout << a.i << " " << b.i << endl;
	b.i = 2;
	cout << a.i << " " << b.i << endl;
	Object::i = 3;
	cout << a.i << " " << b.i << endl;
}
  • 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
  • 35

输出:

10 10
1 1
2 2
3 3
  • 1
  • 2
  • 3
  • 4

上述代码中,Object类中拥有静态变量i,那么对象a和对象b都共享该变量。当该静态变量的值被更改后,对象a和对象b都会获取到被更改之后的新值。

静态成员

静态的类对象和静态变量一样,在声明为static时,空间将在程序的生命周期内分配。

普通类对象的生命周期:

#include <iostream>
using namespace std;

class Object
{
public:
    Object()
    {
        cout << "Inside Constructor
";
    }
    ~Object()
    {
        cout << "Inside Destructor
";
    }
};
int main()
{
	{
		Object a;
	}
	cout << "End of main
";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

输出:

Inside Constructor
Inside Destructor
End of main
  • 1
  • 2
  • 3

静态类对象的声明周期:

#include <iostream>
using namespace std;

class Object
{
public:
    Object()
    {
        cout << "Inside Constructor
";
    }
    ~Object()
    {
        cout << "Inside Destructor
";
    }
};
int main()
{
	{
		static Object a;
	}
	cout << "End of main
";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

输出:

Inside Constructor
End of main
Inside Destructor
  • 1
  • 2
  • 3

通过上面两段代码不难看出,普通的类对象在程序运行到作用范围之外时调用析构函数;静态类对象在程序生命周期结束时,才调用析构函数。

类中的静态函数

类中的静态函数不依赖于类的对象。我们可以使用对象和’.‘来调用静态静态成员函数,但是更推荐使用类名和范围解析运算符’::‘调用静态成员。

class Object
{
public:
    static void print()
    {
        cout << "Hello, Static!
";
    }
};

int main()
{
	Object::print();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

输出:

Hello, Static!
  • 1

单例模式

static变量在C++中是线程安全的。利用该特性可以通过简单的几行代码,在C++中实现一个线程安全的单例类。

#include <iostream>
using namespace std;

template<typename T>
class Singleton
{
private:
	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;
protected:
	Singleton() { }
public:
	static T& Instance()
	{
		static T instance;
		return instance;
	}
	virtual ~Singleton() { }
};

class Object : public Singleton<Object>
{
public:
    void print()
    {
        cout << "Hello, Singleton!
";
    }
};

//main function
int main()
{
	Object::Instance().print();
}
  • 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

输出:

Hello, Singleton!
  • 1
推荐阅读