【C++】特殊类设计+单例模式+类型转换

这篇具有很好参考价值的文章主要介绍了【C++】特殊类设计+单例模式+类型转换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++】特殊类设计+单例模式+类型转换


需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。


 目录

一、设计一个类,不能被拷贝

1、C++98

2、C++11

二、设计一个类,只能在堆上创建对象

1、将构造设为私有

2、将析构设为私有

三、设计一个类,只能在栈上创建对象

四、设计一个类,不能被继承

1、C++98

2、C++11

五、设计一个类,只能创建一个对象(单例模式)

1、饿汉模式设计单例模式

2、懒汉模式设计单例模式

3、单例对象的释放

4、一种比较简洁但是可能存在线程安全的单例懒汉模式

六、类型转换

1、C语言类型转换

2、C++新增四种强制类型转换

2.1static_cast

2.2reinterpret_cast

2.3const_cast

2.4dynamic_cast

3、RTTI


一、设计一个类,不能被拷贝

1、C++98

class CopyBan
{
private:
	CopyBan(const CopyBan& cb);
	CopyBan& operator=(const CopyBan& cb);
};
int main()
{

	return 0;
}

        1、将拷贝构造和赋值运算符重载设置为私有;

        2、仅仅私有还不够,这并不能防止类内部就行拷贝。还要对拷贝构造和赋值运算符重载只声明却不实现。

2、C++11

class CopyBan
{
	CopyBan(const CopyBan& cb) = delete;
	CopyBan& operator=(const CopyBan& cb) = delete;
};

        C++11直接使用delete禁用拷贝构造和赋值运算符重载。

二、设计一个类,只能在堆上创建对象

1、将构造设为私有

【C++】特殊类设计+单例模式+类型转换

        1、将构造设为私有,防止外部构造,并提供一个CreateObj的函数用于构造堆区对象;

        2、但是外部需要对象来调用CreateObj函数来构造对象,所以需要将CreateObj设置为静态函数,无需对象也能调用。

        3、外部通过CreateObj函数构造一个对象后,外部可以利用这个对象的指针拷贝构造一个栈区的对象,需要禁用拷贝构造。

2、将析构设为私有

【C++】特殊类设计+单例模式+类型转换

        将析构函数设置为私有,栈区对象由于无法析构所以无法创建。堆区对象需要手动调用自己写的清理函数释放。

三、设计一个类,只能在栈上创建对象

【C++】特殊类设计+单例模式+类型转换

        1、将构造函数私有;

        2、提供一个静态的CreateObj方法用于构造栈区对象;

        3、但是无法防止外部构造静态对象。

        4、如果想彻底禁止生成静态的对象,需要再禁用拷贝构造。不过这样这个类只能生成临时对象或者引用的对象了,不能修改。

四、设计一个类,不能被继承

1、C++98

class FinalClass
{
	static FinalClass CreateObj()
	{
		return FinalClass();
	}
private:
	FinalClass()
	{}
};

        1、禁用构造函数;

        2、提供一个静态的CreateObj函数供外部创建父类对象,但是子类会因为构造私有的继承不可见的原因无法构造出父类对象,所以无法继承。

2、C++11

class FinalClass final
{
private:
	
};

        C++11直接使用final关键字

五、设计一个类,只能创建一个对象(单例模式)

        一个类只能创建一个对象,即单例模式。该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

1、饿汉模式设计单例模式

class InfoSingleton
{
public:
	static InfoSingleton& GetInstance()
	{
		return _sins;
	}
	void Insert(string name, int money)
	{
		_info[name] = money;
	}
	void Print()
	{
		for (auto kv : _info)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}
private:
	InfoSingleton()
	{}
	InfoSingleton(const InfoSingleton&) = delete;
	InfoSingleton& operator=(const InfoSingleton&) = delete;
	map<string, int> _info;
	static InfoSingleton _sins;
};
InfoSingleton InfoSingleton::_sins;
int main()
{
	InfoSingleton& s = InfoSingleton::GetInstance();//使用单例对象
	s.Insert("小明", 100);
	s.Insert("小红", 50);
	s.Insert("小绿", 130);
	s.Print();
	cout << endl;
	s.Insert("小绿", 10086);
	s.Print();
	return 0;
}

        饿汉模式:在main函数被加载之前就创建好对象。(全局和静态将在main函数之前被加载)

        1、私有构造函数,禁用拷贝构造和赋值运算符重载;

        2、在类中声明、外部定义一个静态的对象,用于调用类中私有的构造函数,同时作为单例对象被使用;

        3、在类中提供一个获取静态对象的函数GetInstance,为了外部可调用,所以将该函数设置为静态。

饿汉模式的特点:

1、单例对象初始化时,数据太多会导致启动慢;

2、如果多个单例类有初始化的依赖关系,饿汉模式无法控制。例如A和B都是单例类,因为B的启动依赖A,所以需要先初始化A,再初始化B,但是饿汉模式无法控制对象的初始化顺序。

3、饿汉模式创建的对象绝对不会有线程安全问题,因为该模式的对象在main函数之前已经被创建好了,mian函数之前线程都没启动呢。

2、懒汉模式设计单例模式

【C++】特殊类设计+单例模式+类型转换

        懒汉模式:第一次获取单例对象的时候创建对象;

        1、私有构造函数,禁用拷贝构造和赋值运算符重载;

        2、在类中声明、外部定义一个静态的对象指针

        3、在类中提供一个获取静态对象的函数GetInstance,为了外部可调用,所以将该函数设置为静态。

        4、它与饿汉的写法区别如图红色标记处。

懒汉模式的特点:

1、对象在main函数之后才会创建;

2、可以主动控制对象的创建时机。

3、创建对象时存在线程安全问题,如果多个线程同时进入红框区域,会可能new多个对象,最后一个创建的对象指针会覆盖之前创建的对象指针,导致内存泄露。

        懒汉模式需要加锁解决线程安全问题:

【C++】特殊类设计+单例模式+类型转换

        不过红框中new也可能会失败,再套一层try/catch看着太累,可以使用RAII锁解决:

【C++】特殊类设计+单例模式+类型转换

        new这里还要try一下异常,main里函数捕获这个异常。(写漏了)

3、单例对象的释放

        1、一般单例对象不需要考虑释放,资源会在进程结束时自动释放;

        2、释放的写法如下:可以手动清理,将一些资源保存:可手动调用DelInstance进行资源的回收,main函数结束时,操作系统也会自动回收单例对象的资源。

【C++】特殊类设计+单例模式+类型转换

4、一种比较简洁但是可能存在线程安全的单例懒汉模式

class InfoSingleton
{
public:
	static InfoSingleton& GetInstance()
	{
		//静态局部变量是在main函数之后才创建初始化
		static InfoSingleton sinst;
		return sinst;
	}
	void Insert(string name, int money)
	{
		_info[name] = money;
	}
	void Print()
	{
		for (auto kv : _info)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}
private:
	InfoSingleton()
	{}
	InfoSingleton(const InfoSingleton&) = delete;
	InfoSingleton& operator=(const InfoSingleton&) = delete;
	map<string, int> _info;
};

        1、私有构造函数,禁用拷贝构造和赋值运算符重载;

        2、通过GetInstance返回静态对象(静态局部变量是在main函数之后才创建初始化)

这种方式构建的单例懒汉模式在C++11发布之前会有线程安全问题,多线程环境下可能会造成静态对象被初始化多次;而C++11规定静态局部变量是线程安全的,可以放心使用。 

六、类型转换

1、C语言类型转换

        1、隐式类型转换2、强制类型转换。

2、C++新增四种强制类型转换

        C++尤其认为隐式类型转化有些情况下可能会出问题:比如数据精度丢失。

2.1static_cast

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);
	cout << a << endl;
	return 0;
}

static_cast适用于相似类型的转换。(可以隐式类型转换的都能用static_cast) 

2.2reinterpret_cast

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);
	cout << a << endl;
	// 这里使用static_cast会报错,应该使用reinterpret_cast
	//int *p = static_cast<int*>(a);
	int* p = reinterpret_cast<int*>(a);
	return 0;
}

reinterpret_cast适用于不相关类型之间的转换。(不能隐式类型转换,只能强制类型转换的用reinterpret_cast)

2.3const_cast

【C++】特殊类设计+单例模式+类型转换

const_cast用于删除变量的const属性。需要关注内存可见性问题。 

        编译器对const变量会有优化,认为const变量不会被改变,编译器在优化代码时可能会将变量放到寄存器或者其他高速缓存中。可以在a初始化时加上volatile关键字,加了volatile关键字后,对变量的读取和写入操作会从内存中进行,而不是从缓存中进行。

2.4dynamic_cast

        dynamic_cast用于父类的指针和引用转换为子类对象的指针和引用。(动态转换)

        向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)

        向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

class A
{
public:
	virtual void f() {}
	int _a = 0;
};
class B : public A
{
public:
	int _b = 0;
};
void fun(A* ptr)
{
	//B* bptr = (B*)ptr;//直接转换是不安全的,父给子存在非法访问隐患
	B* bptr = dynamic_cast<B*>(ptr);
	if (bptr)//如果转换成功
	{
		bptr->_a++;
		bptr->_b++;
		cout << bptr->_a;
		cout << bptr->_b;
	}
}
int main()
{
	A aa;
	B bb;
	fun(&aa);//转换失败
	fun(&bb);//转换成功
	return 0;
}

注意:

1. dynamic_cast只能用于父类含有虚函数的类

2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

3、RTTI

        RTTI:Run-time Type identifification的简称,即:运行时类型识别。

        C++通过以下方式来支持RTTI:文章来源地址https://www.toymoban.com/news/detail-461786.html

1. typeid运算符 
2. dynamic_cast运算符 
3. decltype

到了这里,关于【C++】特殊类设计+单例模式+类型转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++特殊类设计&&类型转换

    在普通类的设计基础上,提出一些限制条件设计的类就是特殊类。 拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝, 只需让该类 不能调用拷贝构造函数 以及 赋值运算符重载 即可。  C++98中的方式: 将拷贝构造函数与赋值运算符

    2024年01月16日
    浏览(32)
  • C++特殊类设计及类型转换

    目录 一、特殊类的设计 1.不能被拷贝的类 2.只能在堆区构建对象的类 3.只能在栈区构建对象的类 4.不能被继承的类 二、单例模式 1.饿汉模式 2.懒汉模式 3.线程安全 4.单例的释放 三、C++类型转换 1.C语言的类型转换 2.static_cast 3.reinterpret_cast 4.const_cast 5.dynamic_cast 6.总结 特殊类就

    2024年02月17日
    浏览(31)
  • 【C++】特殊类的设计 | 类型转换

    设计模式是 被反复使用 多数人知晓 经过分类的、代码设计经验的总结 单例模式: 一个类只能创建一个对象 即单例模式,该模式可以保证系统中该类只有一个实例 单例模式分为饿汉模式和懒汉模式 饿汉模式 一开始就创建对象(main函数之前) 假设想要vector数组全局只有一份

    2024年02月15日
    浏览(27)
  • C++中特殊类的设计与单例模式的简易实现

    对于这种特殊类的设计我们一般都是优先考虑私有构造函数。 然后对于一些特殊要求就直接通过静态成员函数的实现来完成。  这里选择禁掉拷贝构造函数和拷贝函数是为了防止将已创建的对象去拷贝构造新的对象。  这里如果没有禁掉operator new和operator delete的话就会导致以

    2024年01月18日
    浏览(36)
  • C++特殊类的设计与类型转换

    通过new创建的类就是堆上的。 方法一: 这里主要以封禁构造函数为主,让外部只能通过调用func函数方式去创建对象,func函数的内部是通过new创建的,这里要注意的就是拷贝构造的问题。 赋值重载不用删除,因为需要现有一个对象才能赋值给另一个对象,上面的代码只会创

    2024年02月08日
    浏览(25)
  • c++学习之特殊类设计与类型转换

    方法:c++98,通过私有且只申明不实现拷贝构造与赋值函数,从而实现该类不能被拷贝。c++11引入delete后,可以使构造构造与赋值函数等于delete。效果也是无法被拷贝。 方法一,析构私有化 方法二,构造私有化 方法一: 还是构造私有化,但是注意拷贝构造,我们拷贝

    2024年01月20日
    浏览(32)
  • C++:特殊类的设计和类型转换

    1.设计一个类,不能被拷贝 拷贝只会放生在两个场景中: 拷贝构造函数以及赋值运算符重载 ,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 2.设计一个类,只能在堆上创建对象 两种实现方式: 将类的 构造函数私有 , 拷贝构造声

    2024年01月24日
    浏览(42)
  • 【C++】特殊类设计+类型转换+IO流

    🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘 。 🛸 C++专栏 : C++内功修炼基地 家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真

    2024年02月05日
    浏览(32)
  • C++:特殊类和单例模式

    设计一个不能被拷贝的类,通常来说方法就是把拷贝构造和赋值重载都设置为私有,这样就不能进行拷贝了 对于C++11来说,新增了delete的用法,可以直接删除这个函数,也能做到相同的效果 这是一个比较奇怪的要求,但是也有对应实现的方法: 把类的构造函数设置为私有 提

    2024年01月18日
    浏览(45)
  • 【重点:单例模式】特殊类设计

    方式如下: 将构造函数设置为私有,防止外部直接调用构造函数在栈上创建对象。 向外部提供一个获取对象的static接口,该接口在堆上创建一个对象并返回。 将拷贝构造函数设置为私有,并且只声明不实现,防止外部调用拷贝构造函数在栈上创建对象。 说明一下: 向外部

    2024年02月15日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包