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

发布时间:2024年01月18日

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,可以是这个类不能为继承,即最终类。

类型转换

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);

注意:类型转换中间会产生临时变量,二临时变量具有常性,是不能被修改的(引用)。

RTTI(了解)

RTTI Run-time Type identification 的简称,即:运行时类型识别。
C++ 通过以下方式来支持 RTTI
1. typeid 运算符
2. dynamic_cast 运算符
3. decltype
文章来源:https://blog.csdn.net/qq_61422622/article/details/134958740
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。