当运算符两边的变量类型不一致的时候就需要发生类型转换,类型转换有隐式类型转换和强制类型转换,c语言提供的强制类型转换比较简洁,但是还不够规范,可读性不高,所以C++就增加了更加规范的强制类型转换方法.
static_cast用于类型相关的类型之间的转换.
int main()
{
int a = 10;
double b = 11.1;
a = static_cast<int>(b);
cout << a << endl;
return 0;
}
reinterpret_cast是C++中的一种类型转换操作符,它用于在不同类型之间进行强制类型转换,尤其在涉及指针类型的转换时非常有用。它主要用于以下几种情况:
需要注意的是,reinterpret_cast执行的是一种底层的、不安全的类型转换,它会忽略类型之间的任何关系和限制。因此,在使用reinterpret_cast时要格外小心,确保转换的类型和目标类型之间存在合理的关系,以避免潜在的错误和不确定行为。
int a = 10;
string str("string");
string* pstr = &str;
a = reinterpret_cast<int>(pstr);
printf("0x%x\n", a);
const_cast只能用于去除指针或引用类型的常量属性。
volatile 是一个关键字,用于修饰变量,用于告诉编译器该变量可能会被意外的改变,因此编译器在编译时不能对该变量进行优化。
当一个变量被声明为 volatile,意味着该变量可能会被其他线程、中断或硬件设备修改,编译器会确保每次访问该变量时都会从内存中读取最新的值,而不会使用之前缓存的值。
int main()
{
//不加volatile编译器会优化,流提取中a的值
volatile const int a = 10;
int *b = const_cast<int*>(&a);
*b = 20;
cout << a << endl;
return 0;
}
dynamic_cast是C++中用于运行时类型识别和转换的操作符。它主要用于在继承关系中进行安全的向下转型(downcasting)。其中,目标类型是你希望将表达式转换成的类型,表达式是要被转换的对象或指针。
dynamic_cast的用法示例:
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {
public:
void specificFunction() {
// ...
}
};
int main() {
Base* basePtr = new Derived();
// 使用dynamic_cast将basePtr转换为Derived指针
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr) {
// 转换成功,可以调用Derived类的特定函数
derivedPtr->specificFunction();
} else {
// 转换失败,basePtr指向的对象不是Derived类型
// 处理转换失败的情况
}
delete basePtr;
return 0;
}
需要注意的是:
“流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据( 其单位可以是bit,byte,packet )的抽象描述。
C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。
它的特性是:有序连续、具有方向性
C++标准库提供了4个全局流对象cin、cout、cerr、clog;cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
clog和cerr都是标准错误,都是向错误设备输出错误信息,但是clog有行缓冲,cerr没有缓冲.
cin对象支持类型转换为bool类型的,用于逻辑比较,因为cin类中实现了bool类型重载.当对象进行隐式类型转换的时候,编译器首先会先找对应的单参数构造函数,其次是类型重载函数.
#include
#include
#include
using namespace std;
class A
{
public:
A(int a)
:_a(a)
{}
operator int() const
{
return _a;
}
private:
int _a;
};
int main()
{
// 内置类型转换成自定义类型
//A aa1 = static_cast(1);
A aa1 = 1;
// 自定义类转换成内置类型
int x = aa1;
return 0;
}
class Date
{
friend ostream& operator << (ostream& out, const Date& d);
friend istream& operator >> (istream& in, Date& d);
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{}
operator bool() const
{
// 这里是随意写的,假设输入_year为0,则结束
if (_year == 0)
return false;
else
return true;
}
private:
int _year;
int _month;
int _day;
};
istream& operator >> (istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream& operator << (ostream& out, const Date& d)
{
out << d._year << " " << d._month << " " << d._day;
return out;
}
文件流有三个类用于文件的读写**,ifstream和fstream以及ofstream**,它们都是继承了io_base类的写法,在io_base类中定义了in和out两个全局静态对象,用于确定文件是读还是写.因为io_base是三个文件读写类的基类,所以这三个类域中都继承了in和out对象,ifstream用于文件读取,ofstream用于文件写入,fstream同时具备ifstream和ofstream的功能.
**构造:**有无参构造和初始化构造两种,无参构造是先创建对象,然后再打开文件.初始化构造是在构造对象的时候就打开文件.
打开文件的模式有读方式in和写方式out,app和ate以及trunc与binary模式;ate(append to end)是文件流打开模式的一种选项,它将文件流的初始位置设置为文件末尾。这意味着在读/写操作之前,文件指针将定位在文件的末尾,可以直接进行写入操作。如果文件不存在,则会创建一个新文件。
app与ate类似,将文件流的初始位置设置为文件末尾,不同的是,app模式下的写入操作将始终追加到文件的末尾,而不管文件指针的位置。如果文件不存在,则会创建一个新文件。
ate允许在追加之前进行随机访问,而app则始终将写入操作追加到文件末尾。trunc模式作用是清空文件之前的内容.binary用于二进制数据的读写.
需要注意的是在进行二进制文件读写的时候,读写文件不可以是string对象,因为写入的是string对象中的str指针,而不是str本身,当程序结束时str指针会被析构成野指针,所以会导致程序崩溃.
#include
#include
#include
using namespace std;
class Date
{
friend ostream& operator << (ostream& out, const Date& d);
friend istream& operator >> (istream& in, Date& d);
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{}
operator bool() const
{
// 这里是随意写的,假设输入_year为0,则结束
if (_year == 0)
return false;
else
return true;
}
private:
int _year;
int _month;
int _day;
};
struct ServerInfo
{
//char _address[32];
string _address;
int _port;
Date _date;
};
struct ConfigManager
{
public:
ConfigManager(const char* filename)
:_filename(filename)
{}
// 二进制读写,读写对象中,不能有string
void WriteBin(const ServerInfo& info)
{
ofstream ofs(_filename, ofstream::out | ofstream::binary);
ofs.write((char*)&info, sizeof(info));
}
void ReadBin(ServerInfo& info)
{
ifstream ifs(_filename, ofstream::in | ofstream::binary);
ifs.read((char*)&info, sizeof(info));
}
// 文本读写 C++文本读写更简单
// 文本读写本质,内存中任何类型都是转成字符串在写
// c语言文本读写很不方便,因为要不断转字符串
// c++封装了以后就有很大的优势
void WriteText(const ServerInfo& info)
{
ofstream ofs(_filename);
ofs << info._address << " ";
ofs << info._port << endl;
ofs << info._date << endl;
}
void ReadText(ServerInfo& info)
{
ifstream ifs(_filename);
ifs >> info._address;
ifs >> info._port;
ifs >> info._date;
}
private:
string _filename; // 配置文件
};
int main()
{
ServerInfo winfo = { "192.0.0.1xxxxxxxxxxxxxxxxxxxxx", 80, { 2023, 7, 11 } };
string str;
cin >> str;
if (str == "二进制写")
{
ConfigManager cm("test.txt");
cm.WriteBin(winfo);
}
else if (str == "二进制读")
{
ServerInfo rinfo;
ConfigManager cm("test.txt");
cm.ReadBin(rinfo);
cout << rinfo._address << endl;
cout << rinfo._port << endl;
cout << rinfo._date << endl;
}
else if (str == "文本写")
{
ConfigManager cm("test.txt");
cm.WriteText(winfo);
}
else if (str == "文本读")
{
ServerInfo rinfo;
ConfigManager cm("test.txt");
cm.ReadText(rinfo);
cout << rinfo._address << endl;
cout << rinfo._port << endl;
cout << rinfo._date << endl;
}
return 0;
}
构造函数有默认构造,有缺省参数打开模式参数,默认为in,带参构造,string对象加缺省参数打开模式参数,默认为in.
默认构造
explicit istringstream (ios_base::openmode which = ios_base::in);
带参构造
explicit istringstream (const string& str,ios_base::openmode which = ios_base::in);
str成员函数,用于获取或设置stringstream对象的字符串内容
stringstream可以将将数值类型数据格式化为字符串,也可以拼接字符串,也可以分割序列化字符串,格式化数据在格式化的时候应该用空格或者换行隔开.
int main()
{
ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧" };
stringstream oss;
oss << winfo._name << " ";
oss << winfo._id << " ";
oss << winfo._date << " ";
oss << winfo._msg;
string str = oss.str();
cout << str << endl;
stringstream iss(str);
ChatInfo rinfo;
iss >> rinfo._name;
iss >> rinfo._id;
iss >> rinfo._date;
iss >> rinfo._msg;
cout << "-------------------------------------------------------" << endl;
cout << "姓名:" << rinfo._name << "(" << rinfo._id << ") ";
cout << rinfo._date << endl;
cout << rinfo._name << ":>" << rinfo._msg << endl;
cout << "-------------------------------------------------------" << endl;
return 0;
}