C++学习笔记(2)

六、C++指针

1、指针是个啥

指针是一个整数,一种存储内存地址的数字。所谓的数据类型(int,double等)与指针没有直接的关系,所有类型的指针都是保存内存地址的整数
如下代码,设置变量var的初始值为8,并用取地址符**&**把变量var的地址赋值给指针ptr。

#include<iostream>
#define LOG(x) std::cout<<x<<std::endl

int main()
{
	int var = 8;
	void* ptr = &var;
	std::cin.get();
}

2、指针的逆用

逆向引用(*)一个指针,我们可以访问它的数据。例如我们把指针ptr所存放的变量var修改为10。
在这里插入图片描述

3、指针指向的内存分配

#include<iostream>

int main()
{
	char* buffer = new char[8];//实际分配8个字节的内存,并返回一个指向那块内存开始的指针
	memset(buffer, 0, 8);//该函数用指定的数据0填充内存块
    delete[]=buffer;//删掉指针对应的内存块
    std::cin.get();
}

我们用new先分配了8个字节的内存,并返回一个指向那块内存开始的指针buffer,然后我们使用一个叫做memset的函数,它的作用是用我们指定的数据填充一个内存块。它首先接受一个指针buffer,这个指针将会是内存块开始的指针,第二个变量代表指定的填充数据0,第三个变量8则代表填充8个字节。最后使用delete[]删除我们分配的内存。

4、指针的指针

假设我有一个变量a来存储内存地址,它指向另一个变量b,这两个指针指向同一个内存地址,这就是所谓指针的指针。

#include<iostream>

int main()
{
	char* buffer = new char[8];
	memset(buffer, 0, 8);
	char** ptr = &buffer;//指针的指针
	delete[] buffer;

	std::cin.get();
}

七、C++引用

1、引用的含义

引用必须引用已经存在的变量,引用本身并不是新的变量,它并不占用内存,它没也有真正的存储空间。

#include<iostream>

#define LOG(x) std::cout<<x<<std::endl

int main()
{
	int a = 5;
	int& ref = a;//给变量a创建了一个引用ref
	ref = 2;
	LOG(a);
	std::cin.get();
}

int&中的&符号实际上是变量声明的一部分,而指针中的&符号是用来获取现有变量的内存地址。ref这个变量实际上并不存在,它可以看作是变量a的别名。对ref进行操作实际上是对a操作

2、引用传递变量

#include<iostream>

#define LOG(x) std::cout<<x<<std::endl

void Increment(int value)
{
	value++;
}
int main()
{
	int a = 5;
	Increment(a);
	LOG(a);
	std::cin.get();//最终变量a输出的值是5,因为只是将a的值拷贝给value
}

我们可以通过指针来传递参数,(*value)先逆向引用地址的值,然后再自增,这样它才会把变量a自增成6。
在这里插入图片描述
还可以通过引用来传递变量,使变量a递增,它的代码更加简洁。
在这里插入图片描述

3、引用规范

  • 一旦我们声明了一个引用,就不能改变它引用的东西。
  • 当我们声明一个引用时,需要对它进行赋值,否则编译器会报错。

八、C++类与结构体的对比

C++的类与结构体基本上没有什么区别,只有一个关于可见度的小区别:类的成员默认private(私有),意思是只有在类里面的其他方法才可以访问,结构体相反。

  • 在类的外部去调用需要设置为public(公有)。
  • 在结构体中默认值却是public(公有),结构体外部也可以访问。
  • C++中存在结构体的原因是为了与C保持向后兼容性。
    在这里插入图片描述

九、C++中的静态(static)

static关键字在C++中有两个含义,这取决上下文:一个是在类或结构体外部使用static关键字,另一种是在类或结构体内部使用static关键字。

  • 类或结构体外部的static,意味着声明为static的符号,链接将只在内部,它只对我们定义它的翻译单元可见
  • 类或结构体内部的static,意味着该变量实际上将与类的所有实例共享内存,静态变量只有一个实例。

1、外部使用static

我们使用惯例s_来表示这个变量是静态的,由于关键字static,这个变量s_Variable只会在这个翻译单元内部链接。静态变量或函数意味着,当需要将这些函数或变量与实际定义的符号链接时,连接器不会在这个翻译单元的作用域之外寻找那个符号定义。
在这里插入图片描述在这里插入图片描述
因为这个s_Variable变量已经在另一个翻译单元(Main.cpp)中定义了,所以我们不能有两个同名的全局变量。

另一种修改的方式是修改Main.cpp中这个变量的实际指向,我们去掉这里的赋值,标识这个变量为extern,这意味着它会在外部翻译单元中寻找s_Variable变量
在这里插入图片描述

2、内部使用static

Main.cpp代码如下,输出2,3和5,8。

#include<iostream>

struct Entity
{
	int x, y;

	void Print()
	{
		std::cout << x << "," << y << std::endl;
	}
};

int main()
{    
	Entity e;
	e.x = 2;
	e.y = 3;

	Entity e1 = { 5,8 };

	e.Print();
	e1.Print();
	
	std::cin.get();
}

如果让变量变成静态的,e1的初始化会失败,因为x,y不再是类成员
在这里插入图片描述详细实验static的内部应用

3、C++的局部静态(local static)

在局部作用域中使用static来声明一个变量。声明一个变量我们需要考虑两种情况:一个是变量的生存期,另一个是变量的作用域
生存期指的是变量实际存在的时间(在内存中存多久),而变量的作用域是指我们可以访问变量的范围。
静态局部(Local static)变量允许我们声明一个变量,它的生存周期基本相当于整个程序的生存期,但是作用范围被限制在作用域内。

#include<iostream>

void Func()
{
    int i = 0;
	i++;
	std::cout << i << std::endl;
}

int main()
{
	Func();
	Func();
	Func();
	Func();
	Func();//输出五个1
	std::cin.get();
}

若在局部作用域中声明为static,被标记为static的变量i生存周期基本和程序相同,并且它被限制在了Func()中。<效果相当于嵌套>
在这里插入图片描述

不使用局部静态创建单例类

  • 单例类是只存在一个实例的类,我们可以创建这个单例类而不使用静态局部作用域。

我需要先创建静态的单例实例,这里是一个指针。为了返回引用必须有一个返回Singleton&的Get函数,它是静态的,然后返回我的实例,这里要放上逆向引用符号*。然后需要声明这个实例,可以把它默认设为空指针。这样我就可以调用Singleton::Get。

#include<iostream>

class Singleton
{
private:
	static Singleton* s_Instance;
public:
	static Singleton& Get() { return *s_Instance; };

	void Hello()
	{
		std::cout << "Hello" << std::endl;
	}
};

Singleton* Singleton::s_Instance = nullptr;

int main()
{
	Singleton::Get().Hello();

	std::cin.get();
}

使用局部静态创建单例类

我们先去掉静态的单例实例,然后去掉实例的外部定义,然后我们可以扩展Get函数来创建static Singleton的实例,然后返回该实例。
在这里插入图片描述如果这里没有static关键字,那么这个单例会在栈上创建,函数作用域结束时就会被销毁。通过添加静态让它的生存期延长到永远。意味着我们每次调用Get,它实际上会构造一个单例实例,接下来的时间只会返回这个已经存在的实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值