c++学习之特殊类设计与类型转换

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

1.设计一个类,无法被拷贝。

方法:c++98,通过私有且只申明不实现拷贝构造与赋值函数,从而实现该类不能被拷贝。c++11引入关键字delete后,可以使构造构造与赋值函数等于delete。效果也是无法被拷贝。

2.设计一个类只能在堆上创建对象。

方法一,析构私有化

//实现一个类,智能在堆上创建对象
class HeapCreat
{
public:
	
	HeapCreat()
	{
		cout << "调用构造" << endl;
	}
	void release()
	{
		delete this;
	}
private:
	//方法一 析构函数私有化   
	~HeapCreat()
	{
		cout << "调用析构" << endl;
	}
	

方法二,构造私有化

class HeapCreat
{
public:
    ~HeapCreat()
	{
		cout << "调用析构" << endl;
	}
	void release()
	{
		delete this;
	}
	static HeapCreat* Creat()
	{
		return new HeapCreat;
	}
    //但是要禁用拷贝构造,拷贝出都在栈上,不在堆上
      HeapCrea(const HeapCrea& p)=delete;
     
private:
	HeapCreat()
	{
		cout << "调用构造" << endl;
	}
	//方案二 构造函数私有化
};

int main()
{
	//构造函数私有化,最开始都初始化不了,因此只能在类里初始化,并且申明为全局,之后调用类里的初始化
	HeapCreat* p = HeapCreat::Creat();
	p->release();
	return 0;

}

3.设计一个类只能在栈上创建对象。

方法一:

还是构造私有化,但是注意拷贝构造,我们拷贝构造可以new,但拷贝构造不能禁用,因为我们需要调用拷贝构造,故有缺陷

//构造私有化
//还是控制构造函数,在类中实现只能在栈上创建。
class HeapCreat
{
public:
    ~HeapCreat()
	{
		cout << "调用析构" << endl;
	}
	
	static HeapCreat Creat()
	{
		return  HeapCreat();
	}
    HeapCreat( HeapCreat& p)=delete;
private:
	HeapCreat()
	{
		cout << "调用构造" << endl;
	}
};

int main()
{
	HeapCreat p = HeapCreat::Creat();
	return 0;
}

方法二,直接不让使用new,申明出new并私有化,或delete.

class HeapCreat
{
public:
    ~HeapCreat()
	{
		cout << "调用析构" << endl;
	}
	
	static HeapCreat Creat()
	{
		return  HeapCreat();
	}
	void* operator new(size_t t) = delete;
	
private:
	//void* operator new(size_t t) 
	HeapCreat()
	{
		cout << "调用构造" << endl;
	}
};

4.设计一个类,不能被继承

同上,构造函数私有化,调不了就无法被继承。

c++11提供了关键字final,可以是这个类不能为继承,即最终类。

 一,何为设计模式

    设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。设计模式代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。就是前人总结下来的一些经验。

设计模式分为三大类:创建型模式、结构型模式和行为型模式。

创建型模式包括工厂方法模式、抽象工厂模式、单例模式、建造者模式和原型模式。结构型模式包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。行为型模式包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

而创作型中常用的就是我们的单例模式,我们以学习单例模式来了解一下设计模式。

二,单例模式

所谓的单例模式其实本质上就是一个特殊类的设计。对于单例模式,在整个进程中,在整个全局环境中,只有这一个实例化的对象,即单实例,对于这样的类的设计就是单例模式。对于大一点的项目,内存池等都会用到单例模式。

那么如是设计出全局下只有一个实例化对象?参考前面的博客,,特殊类的设计,那么要想只能实例化出一个对象,且是在全局的环境下,首先,我们要控制构造函数,让其私有化,这样在外面就无法实例化,对于构造提供了两种方式,也就是单例模式的两种模式。

其次就是要求在全局环境下的对象,直接在全局下创建首先无法实例化,构造函数已经私有化了,

且全局的对象是存在弊端的:对象是容易被修改的,多线程下会出现链接问题等。

之后了我们在类里创建对象,但直接创建显然不可行,自己创建自己,但是当我们使用ststic时,就不是自己创建自己,该对象是在静态区中。

因此最终我们选用静态全局的方式实现单例模式。

饿汉模式

顾名思义,该模式很“饥饿”,我们在进入主程序前,就要把这个特殊类设计好给我,也就是在此之前,把对象给我来用。

class TEST
{
public:
	//一般我们通过接口Getinstance 来获取这个对象

	static TEST* GetInstance()  //对象是静态对象
	{
		return  &test;
	}
	void ADD(const string key, const string val)
	{ 
		dict.insert(make_pair(key, val));
	}

	void Print()
	{
		for (auto it : dict)
		{
			cout << it.first << ":" << it.second<<endl;
		}
	}
private:
 //首先类的成员一般都是私有的,这里以一个字典为例
	map <string, string> dict;
	//私有构造并禁用拷贝与赋值
	TEST()
	{

	}
	TEST(const TEST& p) = delete;
	TEST& operator=(const TEST& p) = delete;

	static TEST test;//声明   在静态区当中
};
//定义
TEST TEST::test;   //定义了一个类的对象test

int main()
{
	//程序启动 饿汉模式
	TEST::GetInstance()->ADD("冒泡", "排序");//通过GetInstance获取唯一的对象test
	TEST::GetInstance()->ADD("希尔", "排序");
	TEST::GetInstance()->Print();
	return 0;
}

优缺点:

优点:实现简单

缺点:可能导致进程启动 ,如果有两个单例启动具有先后顺序,控制不了饿汉。

懒汉模式

顾名思义,现吃现做,只有当我们需要使用这个对象的时候,我们才提供对象。即第一次使用的时候才创建。

//懒汉模式
class TEST
{
public:
	
	static TEST* GetInstance()  
	{
		//主程序要调用使用对象了此时我们在创建
		//这里主要介绍懒汉的思想,实际上这里的代码还存在线程安全问题
		if (test == nullptr)
		{
			test = new TEST;
		}
		return test;
	}
	void ADD(const string key, const string val)
	{ 
		dict.insert(make_pair(key, val));
	}

	void Print()
	{
		for (auto it : dict)
		{
			cout << it.first << ":" << it.second<<endl;
		}
	}
	static void Delete()
	{
		if (test)
		{
			delete test;
			test = nullptr;
		}
	}
	
private:
 //这里以一个字典为例
	map <string, string> dict;
    ~TEST()
	{
		delete test;
	}
	TEST()
	{

	}
	TEST(const TEST& p) = delete;
	TEST& operator=(const TEST& p) = delete;
	static TEST *test;//声明   在静态区当中
	class gc
	{
	public:
		~gc()
		{
			Delete();
		}
		
	};
	static gc _gc;
};
//定义
TEST* TEST::test=nullptr;  
TEST::gc  TEST::_gc;

int main()
{
	//程序启动 
	//懒汉模式
	TEST::GetInstance()->ADD("冒泡", "排序");//通过GetInstance获取唯一的对象test
	TEST::GetInstance()->ADD("希尔", "排序");
	TEST::GetInstance()->Print();
	
}

释放的时候,可以使用智能指针来管理这个指针,也可以在搞一个类用来处理析构,在该对象中,只要释放,就会调用里面的类的的析构使得释放指针。

类型转换

c语言中的类型转换

c语言的类型转换分为两种:

1.隐式类型转换  :int i=1;double b=i;

对于能相互转换的类型,可以隐式类型转换。

2.显式类型转换 :  int j=1;doule ret=double(j)/0.1;

有关联性的类型可以强制类型转换。

c++的类型转换

对于c语言的类型转换,c++认为不太规范,因此c++提出了四种强制类型转换的类型,只有这四类的类型才能强转。

C++提供了四种强制类型转换的函数:static_cast、dynamic_cast、const_cast和reinterpret_cast。

下面对这四种转换操作的适用场景分别进行说明:

static_cast(静态转化): 该运算符把 expression 转换为 type 类型,主要用于基本数据类型之间的转换,如把 uint 转换为 int,把 int 转换为 double 等。此外,还可用于类层次结构中,基类和派生类之间指针或引用的转换。

主要用于相近类型的转化(对应c语言的隐式类型转换的类型):

double i = 3.14159265;
int j = static_cast<int> (i) ;

dynamic_cast:(动态转化) 主要用于类层次间的上行转换或下行转换。在进行上行转换时dynamic_cast 和 static_cast 的效果是一样的,但在下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全。

dynamic_cast 用于将一个父类对象的指针 / 引用转换为子类对象的指针或引用 ( 动态转换 )
对于向下转型(即父类给给子类),强制类型转换理论上对象是不可以的,但指针和引用可以。 但是向下转换,存在越界访问的问题,是不安全的。
因此c++提供了dynamic_cast:
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
1. dynamic_cast 只能用于父类含有虚函数的类
i 2. dynamic_cast 会先检查是否能转换成功,能成功则转换,不能则返回 0
注意使用dynamic_cast前提是多态。

const_cast:(常态转化) 该运算符用来修改 expression 的 const 或 volatile 属性。

去调const属性,取地址在强转为普通指针类型。


	const int a = 10;
	int* p = const_cast<int*>(&a);
	*p = 3;

这里的a可能直接放寄存器了,也可能宏定义了。(不再去内存找这个值) 

因此虽然这里&a与p的地址一样,但是值不一样。利用关键字volatile使得强制去内存取值,我们就会发现两个值是一样的。其次在打印&a时,注意用printf,c++中的cout的输出流在打印时没有对应的函数。

reinterpret_cast: (重新诠释转化)该运算符可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。这个转换是“最不安全”的,不推荐使用

有一定关联,但是意义不相似的类型之间的转换


	int a = 1;
	int* ptr = reinterpret_cast<int*> (a);

注意:类型转换中间会产生临时变量,二临时变量具有常性,是不能被修改的(引用)。文章来源地址https://www.toymoban.com/news/detail-808513.html

RTTI(了解)

RTTI Run-time Type identification 的简称,即:运行时类型识别。
C++ 通过以下方式来支持 RTTI
1. typeid 运算符
2. dynamic_cast 运算符
3. decltype

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

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

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

相关文章

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

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。   目录 一、设计一个类,不能被拷贝 1、C++98 2、C++11 二、设计一个类,只能在堆上创建对象 1、将构造设为私有 2、将析构设为

    2024年02月06日
    浏览(53)
  • 【C++】特殊类设计+类型转换+IO流

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

    2024年02月05日
    浏览(44)
  • C++特殊类的设计与类型转换

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

    2024年02月08日
    浏览(40)
  • 从C语言到C++_37(特殊类设计和C++类型转换)单例模式

    目录 1. 特殊类设计 1.1 不能被拷贝的类 1.2 只能在堆上创建的类 1.3 只能在栈上创建的类 1.4 不能被继承的类 1.5 只能创建一个对象的类(单例模式)(重点) 1.5.1 饿汉模式 1.5.2 懒汉模式 2. 类型转换 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3. RTTI(了解)和类型转换常见面

    2024年02月10日
    浏览(49)
  • 【C++】异常+智能指针+特殊类和类型转换

    上天可能觉得我太孤独,派你来和我一起对抗虚无。 1. C语言传统处理错误的方式无非就是返回错误码或者直接是终止运行的程序。例如通过assert来断言,但assert会直接终止程序,用户对于这样的处理方式是难以接受的,比如用户误操作了一下,那app直接就终止退出了吗?这

    2024年02月08日
    浏览(50)
  • 【C++学习笔记】特殊类设计

    C++类中只有两个拷贝的方式:拷贝构造函数和赋值运算符重载。想要设计一个不能被拷贝的类,只要想办法让类中这两种拷贝的方式不能使用即可。 因为在C++的类中,这两种拷贝的方式是默认存在的,所以需要在类中只声明不定义即可。 但是由于在用户在类外还能定义,所

    2024年02月15日
    浏览(45)
  • c++学习(特殊类设计)[30]

    如果你想要确保对象只能在堆上创建,可以通过将析构函数声明为私有,并提供一个静态成员函数来创建对象。这样,类的实例化只能通过调用静态成员函数来完成,而无法直接在栈上创建对象。 以下是一个示例: 在上面的示例中, HeapOnlyClass 类的构造函数和析构函数都被

    2024年02月14日
    浏览(35)
  • 【C++学习】C++4种类型转换详解

    在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。 隐式类型转化:编译器在编译阶段自动进行,能转就转,不

    2024年04月28日
    浏览(32)
  • web前端框架JS学习之JavaScript类型转换

    vascript有多种数据类型,如字符串、数字、布尔等,可以通过typeof语句来查看变量的数据类型。数据类型转换就是数据类型之间相互转换,比如把数字转成字符串、把布尔值转成字符串、把字符串转成数字等,这在工作也是经常碰到的。 本期我们就给大家说说web前端框架JS学

    2024年02月10日
    浏览(64)
  • C++ 特殊类设计

    如果只能在堆上创建对象,就是限制在栈上和静态区中创建对象,步骤如下: 方法一:将构造函数私有化. 将构造函数设置为私有,以防用户在栈上或者静态区直接调用构造函数创建对象. 在公有区域提供一个静态的成员函数,在该静态成员函数中使用new创建对象,此时因为new在成员函

    2024年02月11日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包