c++基础知识整理与分析

const使用

const 修饰指针的情况,因为p、q本身为地址,地址里面存放着值

//const 在*左边,值不能变,但地址可以变
const int* p = new int(10);
int const * p = new int(10);
p = new int(20);

//const在*右边,说明地址不能变,但值可以变
int* const q = new int(20);
*q = 30;

const 修饰函数

class A
{
public:
	const int func1(){}		//返回值不能被修改
	void func2(const int &a){}		//a不能被修改
	void func3() const {}		//函数内使用的成员变量不能被修改	
}

new delete实现原理

new

operator new 与malloc类似,区别在于operator new 在malloc的基础上加了失败抛出异常,
operator new 与new的区别在于,new比operator new多一步调用构造函数。
	1.对于基本类型 new->operator new ->malloc
	2.对于类 new->operator new ->malloc->构造函数

delete

	1.对于基本类型 delete->operator delete->free
	2.对于类 delete->operator delete->free->析构函数

placement new

在事先申请的内存上构造一个新的对象。
int *a = new int(10);		//*a = 10
new(a) int(20);		//*a = 20;

new delete和malloc free的区别

new deletemalloc free
是否需要指定大小01
类型运算符库函数
能否重载10
失败返回异常bad_callocNULL
是否调用构造、析构10
返回类型对象类型void *

内存映像

class Base
{
public:
	void func1()
	{
		cout << "func1 call" << endl;
	}
	static void func2() {}
	void func3() {}
private:
	int data;
	static int s_data;
};

int main()
{
	Base *b = nullptr;
	b->func1();		//此处调用成功,会打印"func1 call"
}
Base类对应的对象内存映像如下图

在这里插入图片描述
static成员变量放在静态区,static和non-static成员函数放在代码段,代码段和静态区只有一份,各类共享。non-static成员变量每个类都有一份。
为什么空的对象指针也能调用成员函数,并且能调用成功?
如上说明,对象与代码段中的函数通过this指针进行绑定,对象能访问成员函数,此处只是将this指针设置为nullptr,而函数实现中并没有使用this,因此能调用成功。

继承关系中构造函数/析构函数调用顺序

	在单继承中,构造函数调用关系为 父类构造->子类构造;析构函数调用:子类析构->父类析构
	多继承:按照继承顺序,BaseA->BaseB->C;析构函数:C->BaseB->BaseA
class BaseA
{
};
class BaseB
{};

class C:public BaseA,public BaseB
{
};

多态的实现原理

静态多态(编译时多态)

	静态多态基于函数重载实现,在编译期间就能确定接口具体调用哪个实现。
	函数重载:函数名相同,函数的形参类型或参数个数不同;若形参完全相同,只有返回参数不同,不是函数重载。
	函数重写:函数名、形参个数和类型都相同。
	不同点
区别重载重写
发生条件同一作用域继承时
实际用途扩展实现,提供多个实现版本覆盖实现

动态多态(运行时多态)

	动态动态基于虚函数实现,子继承父类,并且重写父类的虚函数,在使用时,父类指针指向子类对象则调用子
类虚函数,指向父类对象则调用父类虚函数。由于在运行期间才能决定调用哪个实现,则为运行时多态。
	父类指针如何知道该调用父类虚函数还是子类虚函数?
		当类中存在虚函数或存在虚继承关系时,编译器会为对象生成一个虚表,虚表前一个位置存放了一个
	指向type_info指针的地址,type_info存放了继承关系,对象信息等
	虚表:
		每个对象都会有虚表,一般存放在对象的首地址,虚表中存放则虚函数的地址,存放顺序为虚函数的定义顺序,
	父类对象中的虚表存放的父类的虚函数的地址,子类对象的虚表分为几种情况:
		(1)父类中存在的虚函数,子类没重写:存放的还是父类虚函数的地址
		(2)父类中存在的虚函数,子类重写:存放的子类虚函数的地址
		(3)子类新增的虚函数:虚表中追加新的虚函数的地址
	通过代码获取虚表等信息:
class Base
{
public:
	void func1()
	{
		cout << "call func1" << endl;
	}
	virtual void func2()
	{
		cout << "call func2" << endl;
	}
	virtual void func3()
	{
		cout << "call func3" << endl;
	}
};
int main()
{
	Base b;
	cout << "虚表地址:" << (intptr_t*)(&b) << endl;
	auto vptr = *(intptr_t*)(&b);		//虚表指针	
	auto vfuncptr = (intptr_t*)vptr;		//虚函数指针
	cout << "虚函数地址" << vfuncptr << endl;
	typedef void (*f) ();
	f fun1 = (f)vfuncptr[0];	//func2,第一个虚函数
	f fun2 = (f)vfuncptr[1];	//func3,第二个虚函数
}

设计原则

单一职责

	一个类尽量负责单一的任务,减少类的复杂程度,利于扩展和维护。

开闭原则

	一个类尽量能扩展,少修改。以扩展的方式进行功能的修改,保证已有功能在增加功能后还是稳定的。

里氏替换原则

	所有用到子类对象的地方都能替换为父类对象
	子类不能重写父类的非抽象方法。
	子类可以扩展新的接口

依赖倒置

	高层模块(使用接口的类)不依赖底层模块(接口类),都依赖一个抽象接口类
	如下代码,有一个打印类,可以打印其他类中的Wait,目前只有打印书的需求,
	若后面增加一个打印报纸的需求,那就得增加或修改Paint类,这样耦合度就
	太高了,因为打印类根本不用知道其他类,它只管打印,因此不应该进行变动
class Book{
public:
	string Wait()
	{
		return "this is book!";
	}	
};

class Paint{
public:
	void PaintFunc(const Book &b)
	{
		cout<<b.Wait()<<endl;
	}
};
	可以增加一个抽象类,提供一个抽象接口,打印类去依赖抽象接口
class Manage{
public:
	virtual string Wait() = 0;
};

class Book :public Manage{
public:
	string Wait()
	{
		return "this is book!";
	}	
};

class Paint{
public:
	void PaintFunc(Manage *b)
	{
		cout<<b->Wait()<<endl;
	}
};

三级目录

设计模式

单例模式

饿汉模式

优点:代码简单,不用考虑释放内存问题
缺点:程序一启动就会加载资源,资源过多会导致程序启动变慢,且多个单例创建顺序无法控制
class SingleInstance
{
public:
	SingleInstance() = delete;
	~SingleInstance() = delete;
	SingleInstance(const SingleInstance&) = delete;
	SingleInstance& operator=(const SingleInstance&) = delete;
	static SingleInstance* GetInstance()
	{
		return &s;
	}
protected:
private:
	static SingleInstance s;
};

懒汉模式

优点:延迟加载,程序启动无影响,且多个单例创建顺序可以控制
缺点:程序一启动就会加载资源,资源过多会导致程序启动变慢
普通懒汉模式(代码简单、非线程安全)
class SingleInstance
{
public:
	static SingleInstance* GetInstance()
	{
		if (s == nullptr)
		{
			s = new SingleInstance;
		}
		return s;
	}
protected:
private:
	SingleInstance() {}
	~SingleInstance() {}
	SingleInstance(const SingleInstance&) {}
	SingleInstance& operator=(const SingleInstance&) {}

	static SingleInstance *s;
};
SingleInstance *SingleInstance::s = nullptr;
简单加锁(每次都上锁,影响性能,但线程安全)
class SingleInstance
{
public:
	static SingleInstance* GetInstance()
	{
		single_mutex.lock();
		if (s == nullptr)
		{
			s = new SingleInstance;
		}
		single_mutex.unlock();		
		return s;
	}
protected:
private:
	SingleInstance() {}
	~SingleInstance() {}
	SingleInstance(const SingleInstance&) {}
	SingleInstance& operator=(const SingleInstance&) {}

	static SingleInstance *s;
	static mutex single_mutex;
};
SingleInstance *SingleInstance::s = nullptr;
mutex SingleInstance::single_mutex;
复杂加锁(只有在第一次创建的时候才会加锁,线程安全)
class SingleInstance
{
public:
	static SingleInstance* GetInstance()
	{
		if (s == nullptr)		//第一次判断为了只创建一次
		{
			single_mutex.lock();	//多个线程同时到达此处,第一个线程上锁,其他线程等待
			//第二次判断防止多个线程同时调用时,只创建一次,若没有这次判断,
			//第一个线程到这里会创建,然后解锁,第二个等待的线程也会到达这里,再次创建对象,这样第一个
			//设置的参数可能在第二个线程创建对象后消失。
			if (s == nullptr)		
			{
				s = new SingleInstance;
			}
			single_mutex.unlock();
		}
		return s;
	}
protected:
private:
	SingleInstance() {}
	~SingleInstance() {}
	SingleInstance(const SingleInstance&) {}
	SingleInstance& operator=(const SingleInstance&) {}

	static SingleInstance *s;
	static mutex single_mutex;
};
SingleInstance *SingleInstance::s = nullptr;
mutex SingleInstance::single_mutex;

单例释放对象

采用内嵌类的方式进行释放

class SingleInstance
{
public:
	static SingleInstance* GetInstance()
	{
		if (s == nullptr)
		{
			single_mutex.lock();
			if (s == nullptr)
			{
				s = new SingleInstance;
			}
			single_mutex.unlock();
		}
		return s;
	}
	class Garbo {
	public:
		~Garbo()		//释放时调用析构函数
		{
			if (SingleInstance::s == nullptr)		
				delete SingleInstance::s;
		}
	};
protected:
private:
	SingleInstance() {}
	~SingleInstance() {}
	SingleInstance(const SingleInstance&) {}
	SingleInstance& operator=(const SingleInstance&) {}

	static SingleInstance *s;
	static mutex single_mutex;
	static Garbo garbo;		//程序结束会释放该变量
};

SingleInstance *SingleInstance::s = nullptr;
SingleInstance::Garbo SingleInstance::garbo;
mutex SingleInstance::single_mutex;

工厂模式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值