11.21碎片问题
使用C++创建单例模式
之前用多了C#轮椅以为自己就是单例模式懂哥了,结果却抛弃了C++原有的底层知识
#include <iostream>
class Singleton {
public:
// 获取单例实例的静态方法
static Singleton& getInstance() {
// 使用局部静态变量确保线程安全的初始化
static Singleton instance;
return instance;
}
// 删除拷贝构造函数和赋值运算符重载,确保单例不会被复制
Singleton(const Singleton&) = delete;
void operator=(const Singleton&) = delete;
void doSomething() {
std::cout << "Singleton is doing something." << std::endl;
}
private:
// 私有构造函数,确保外部无法直接实例化
Singleton() {
// 进行初始化工作
}
};
int main() {
// 获取单例实例
Singleton& singleton = Singleton::getInstance();
// 使用单例实例
singleton.doSomething();
return 0;
}
delete this
什么情况下要用到呢
- 对象自毁:在对象的成员函数中,如果确定对象在某个条件下需要自毁,可以使用
delete this
。但是需要确保在delete this
之后不再访问对象的任何成员。 - 对象池:在一些特殊的对象池设计中,当对象不再需要时,可以通过调用自身的成员函数来删除自己。
- 异步操作:在一些异步操作中,可能需要在回调函数中删除对象自身。
operator new
与placement new
operator new就是常见的new用法,在堆上分配内存空间并利用对象的构造函数来创建对象,如:
MyClass* obj = new MyClass;
placement new是一个特殊的new,区别时在已经有的空间上创建对象,如
MyClass* obj = new(ptr) MyClass;
就是在ptr指定的内存段上创建对象,不会分配新的内存空间
static
关键字的全面解析,extern
关键字的全面解析
static
对于C、C++、C#中的static的含义其实是大部分一致的,不同的地方取决与语言自身功能性的不同,比如纯C语言不带有的成员函数,那么static在这一方面就不存在意义。
局部变量
普通的局部变量生命周期和其作用域一致,但加上static关键字后该局部变量由栈内存转移到静态存储区,在整个程序的生命周期中都存在,但是对于其他函数来说是不可见的。
全局变量
定义在函数体外部的全局变量整个工程都可见,其他文件使用extern后可直接使用。所以说两个文件不能定义同名的全局变量,除非使用static。
增加static后,该全局变量的作用域就会限制在该文件之内。
函数
在同一个工程中的不同文件中的函数可以直接相互调用,因为在链接的时候会被统一编译链接。对于static则和全局变量一样,使用static的函数只能在定义其的文件中可见。
数据成员
静态数据成员不隶属于任何对象,所有的对象都拥有同一份静态成员,在没用类对象的时候也可以进行操作,也遵顼public等访问规则。
在访问静态数据成员时,访问方式如:
obj.a=1
或者MyClass::a=1
obj为对象,MyClass为类类型
相对于全局变量来说,静态成员不存在于其他全局名字冲突的可能性(显然类名已经做了区分);同时,静态成员变量可以用private隐藏,而全局变量不能。
成员函数
静态成员函数同样不隶属于对象而是隶属于类,其特性是没有this指针(想想就明白了)
C#中的新static
C#中类也可以static,但是静态类的所有成员都必须也是静态的。
extern
如上,如果两个文件(同一工程)想互通全局变量,那么访问文件的使用全局变量需要加上extern关键字。
有一个推荐的方法是文件A正常定义全局变量,然后在文件A中的h文件里加上extern该全局变量的声明,于是其他文件想使用就直接include就可以了——要知道include就是将代码“备份”进去。
extern “C”
它告诉编译器C++按照C方法进行函数名的处理,主要是因为C++支持函数重载而C不支持。
例如C++中
void A(int a);
void A(int a,int b);
这两个函数名相同,但在C++编译器中编译后函数名其实会变化,用来区分两个参数列表不同的重载函数。但C语言中没有这个机制,也就是说在处理这方面两种编译器的措施是不同的,所以在C++中使用C文件函数时要用extern{}来声明:
extern{void A(int a);}
假如A没有重载
确保链接的时候不会发生错误。
纯C语言实现面向对象
纯C函数没有类说法,也没有对象说法,但其实也可以通过一些手段来模拟实现。
- 结构体-->模拟类。
- 函数指针-->在结构体中声明函数指针模拟类方法。
- 封装-->前两者实现封装,也就是数据和相关操作绑定在一起。
- 继承-->结构体中包含指向父类结构体的指针。
- 多态-->函数指针动态绑定来实现(在使用时变化函数指针的指向)。
看起来太笨拙了不是吗?但你就说是不是面向对象嘛