C++ --- 特殊类 --- 类型转换 ---IO流

文章目录

  • 特殊类
    • 不能被拷贝的类
    • 只能在堆上创建的类
    • 只能在栈上创建的类
    • 不能被继承的类
    • 只能创建一个对象的类
      • 饿汉模式
      • 懒汉模式
  • 类型转换
    • 为什么需要四种类型转换
    • static_cast
    • reinterpret_cast
    • const_cast
    • dynamic_cast
  • IO流
    • 什么是流
    • C++标准IO流
    • C++文件IO流

特殊类

不能被拷贝的类

拷贝会有两个场景:

  1. 拷贝构造函数
  2. 赋值运算符重载

因此只需要将这两个禁止掉即可

在C++98中可以将这两个函数设为私有,或者只声明不定义

在C++11中可以在默认成员函数后面加上 =delete 表示将该默认成员函数删除

class A
{
	A(const A&) =delete;
	A& operator=(const A&) =delete;
};

只能在堆上创建的类

可以分两个步骤:

  1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
  2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
class A
{
public:
	static A* create()
	{
		return new A;
	}
private:
	A()
	{}
	
	A(const A&) =delete;
};

只能在栈上创建的类

和只在堆上创建一样,只需要将静态方法返回创建对象即可,并且禁止new

class A
{
public:
	static A create()
	{
		return A();
	}
	
	void* operator new() = delete;
	void operator delete(void* p) = delete;
private:
	A()
	{}
	
	A(const A&) =delete;
};

不能被继承的类

在C++98中需要将构造函数设为私有,这样派生类调用不到基类的构造函数就不能继承

在C++11中可以在类后面加上 final关键字,表示该类不可继承

class A final
{

};

只能创建一个对象的类

这中类就是单例模式,一个类只能创建一个对象,这种单例模式可以保证该类只有一个实例。

这种模式可以有两种实现的方法

饿汉模式

不管用不用得到这个类,只要在程序启动时就创建一个该类的对象

class A
{
public:
    static A* GetInstance()
    {
    	return &m_instance;
    }
private:
    // 构造函数私有
    A(){};

	// 取消拷贝和赋值
    A(A const&) = delete;
    A& operator=(A const&) = delete;
    
    static A m_instance;
};
// 在程序入口就完成对象初始化
A A::m_instance;

懒汉模式

和饿汉模式正好相反,在用到的时候再创建对象

类型转换

为什么需要四种类型转换

C语言的转换风格虽然很简单,但是有不少的缺点

  1. 隐式类型转化有些情况下可能会出现精度丢失的问题
  2. 显式类型转换会将所有情况混合在一起,导致代码不够清晰

因此C++就提出了自己的转换风格,并且C++兼容C语言,所以C++中也可以使用C语言的风格

static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用,但是不能用于两个不相关的类型进行转换

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

reinterpret_cast

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

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

const_cast

const_cast最常用的用途就是删除变量的const属性方便赋值

int main()
{
    const int a = 2;
    int* p = const_cast< int*>(&a );
    *p = 3;
    cout<<a <<endl;
    
    return 0;
}

dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)

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

向下转型:父类对象指针/引用 -> 子类指针/引用 (需要用dynamic_cast转型)

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

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

class A
{
public :
	virtual void f(){}
};

class B : public A
{};

void fun (A* pa)
{
    // dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
    B* pb1 = static_cast<B*>(pa);
    B* pb2 = dynamic_cast<B*>(pa);
    
    cout<<"pb1:" <<pb1<< endl;
    cout<<"pb2:" <<pb2<< endl;
}
int main ()
{
    A a;
    B b;
    fun(&a);
    fun(&b);
    
    return 0;
}

IO流

什么是流

流:是对一种有序连续且具有方向性的数据( 其单位可以是bit,byte,packet )的抽象描述

C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程

C++标准IO流

C++标准库提供了4个全局流对象cin、cout、cerr、clog,使用cout进行标准输出,即数据从内存流向控制台(显示器)。使用cin进行标准输入即数据通过键盘输入到程序中,同时C++标准库还提供了cerr用来进行标准错误的输出,以及clog进行日志的输出

  1. cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据
  2. 输入的数据类型必须与要提取的数据类型一致
  3. 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入
  4. 如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格,回车符也无法读入
  5. cin和cout可以直接输入和输出内置类型数据,对于自定义类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载

C++文件IO流

C++根据文件内容的数据格式分为二进制文件和文本文件

  1. ifstream ifile(只输入用)
    ofstream ofile(只输出用)
    fstream iofile(既输入又输出用)
  2. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
  3. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写

C++文件流的优势就是可以对内置类型和自定义类型,都使用一样的方式,去流插入和流提取数据

你可能感兴趣的:(C++,c++,开发语言)