c++知识点总结
基本功能
#include<iostream>//头文件
using namespace std;//使所有的std名字都可用,不必加std::前缀
1. 类型和声明
类型
基本类型 | 所占字节 | 可能的值 |
---|---|---|
int | 4 | 1 |
bool | 1 | true、false |
char | 1 | ‘a’ |
double | 8 | 3.14 |
string | “hello!” | |
* | 4 | 指针 |
[] | 数组 | |
& | 引用 | |
() | 函数 | |
enum | 枚举{ , ,} |
int,long int,short int的宽度都可能随编译器而异。但有几条铁定的原则(ANSI/ISO制订的):
- sizeof(short int)<=sizeof(int)
- sizeof(int)<=sizeof(long int)
- short int至少应为16位(2字节)
- long int至少应为32位。
- sizeof()用来计算所占字节数
1Byte(字节) = 8bit(比特) = 1B = 8b(8个二进制位/比特位)
bool类型 true=1,false=0
在算数和逻辑表达式里,bool都将会被转换为int,在这种转换之后得到的值上进行各种算数和逻辑运算。如果最后的结果又被转回到bool,那么0=false,1=true
指针也可以隐式转换到bool,非零指针转为true,具有零值的指针转化为false
bool b=7;//bool(7)是非零,所以这里b=1;
int i=true;//true是1,所以这里i=1;
字符型变量可以保存一个字符
char ch='a';//8个二进制位,所以可以保存256种不同的值
//每一个字符常量都有一个整数值,对应ASCII。'a'=97;
int main()
{
char c;
cin>>c;
cout<<int(c)<<endl;//输出ASCII码
}
每一个枚举的类型都是一个独立的类型,枚举符的类型就是它所在的那个枚举
enum keyword{ ASM,AUTO,BREAK};
//枚举所赋的值从0开始递增,ASM=0,AUTO=1等
运算符(常见的不列出) | 含义 |
---|---|
% | 取余 |
== | 等于 |
!= | 不等于 |
<< | 输出(cout) |
>> | 输入(cin) |
“\n” <<endl | 换行 |
& | 取地址、引用 |
\t | 水平制表符 |
:: | 作用域解析 |
objec.member | 成员选择 |
pointer—>member | 成员选择 |
(type)expr | 强制类型转换 |
sizeof(type) | 类型的大小 |
new type(expr-list) | 建立(初始化) |
delete []pointer | 销毁数组 |
expr?expr:expr | 条件表达式 |
throw expr | 抛出异常 |
像在c中一样,=是赋值符号,而==检测相等
声明
- 每一个变量使用前必须声明
- 在一个声明中不能没有类型
- 用逗号分隔开多个声明
- 运算符只作用于一个单独的名字
- int *p,y;//只有p是指针,而是整型,要避免这样声明
- 自定义类型首字母大写
- 宏全部大写(NULL)
- 命名最好用英语直译
作用域
在函数里声明的名字(局部),其作用域从它声明的那一点开始,知道这个声明所在的块全部结束为止,一个块就是由{ }围起来的一段代码。
全局的声明,作用域从声明那一点开始直到文件结束。
在一个块里可以重新声明一个和全局变量同名的名字,在这个块里会隐蔽掉全局变量(要尽量规避这种情况,容易出现bug)
typedef
为类型声明了一个新的名字,而不是声明一个指定类型的对象
typedef char* Pchar;//为类型声明了一个新的名字,而不是声明一个指定类型的对象
Pchar p1,p2;//p1和p2都是char *
2. 指针、数组和结构
指针
指针定义
char *p;//指向字符的指针
p=&v[3];//p指向v的第四个元素
如何理解指针?
- 普通变量存放某一类值,地址变量(指针)存放地址。
- 指针就是一个存放地址的变量,*p解引用指针的值就是该地址里放的东西。
在应用于指针时,==比较的是地址(指针的值),而不是被指向的东西
数组
对于类型T,T[size]就是“具有size个T类型的元素的数组” 下标从0到size-1
- 数组大小必须是常量表达式
- 多维数组被表示为数组的数组(int d2[10][20];d2是一个包含10个各包含20个整数的数组的数组)
- 在底层代码中之外最好避免使用多维数组
字符串文字
char *a=“this is a string”;
sizeof(“bohr”)=5;多一个\0
- 字符串文字类型是“适当个数的const字符的数组”,所以“bohr”的类型就是const char[5]
- 字符串文字是静态分配的,所以让函数返回它们是安全的
到数组的指针
一个数组的名字可以看作是开始元素的指针
常量
const
const可以加到一个对象的声明上,将这个对象声明为一个常量。因为之后不允许赋值,所以常量一开始就要初始化
const int model=90;//model是一个常量
const int v[]={1,2,3,4};//
const int x;//错误,没有初始化
将某些东西声明为常量,就保证了在其作用域内不能改变它们的值
指针和常量
void f1(char *p)
{
char s[]="Gorm";
const char *pc=s;//指向常量
pc[3]='g';//错误,常量不可以改变
pc=p;//ok
char *const cp=s;//指针常量
cp[3]='a';//ok
cp=p;//错误,指针不可改变
const char *const cpc=s;//指针常量,同是指向的对象也是常量
cpc[3]='a';//均不可以改变
cpc=p;
}
引用
引用就是取别名,主要用途是为了描述函数的参数和返回值
- 为了确保一个引用就是某对象的名字,引用必须初始化
- 引用初始化之后不可更改,就只能引用初始化所指的那个对象
- 引用最直接的实现方式是指针常量,指向的值可以更改,而指针指向的位置不可以更改
结构
struct{ };在花括号之后要加上分号
struct address{
char *name;
long int number;
char *street;
};
//每个成员可以用原点访问到:addre.name
结构对象常常通过指针用->运算符访问
p->name等价于(*p).name地址变量指针用->,一般变量用.
struct是class的简单形式
3. 表达式和语句
如果不了解运算优先级,加括号是最保险的方法
也可以通过把复杂的表达式分开的写法
++ i 先计算后调用i,i ++ 先调用后计算
用new来建立一个新的数组
char *save_string(const char *p)
{
char *s=new cha[strlen(p)+1];//建立一个比p大1的数组
strcpy(s,p);//将p的值copy给s
return s;
}
int main(int argc,char *argv[])
{
if(arge<2)
exit(1);
char*p = save_string(argv[1]);
//...
delete []p;//删除数组需要加[]
}
为了释放由new分配的空间,delete和delete[]必须能够确定为对象分配的空间大小,这也一位置通过标准实现的new分配的对象将占用比静态对象稍微大一点的空间。在典型情况下需要用一个机器字保存对象的大小
语句
选择语句
if(condition) statement;//如果condition为真,执行第一个语句
else statement;//否则执行第二个语句
switch(condition)
case condition://看condition的值来判断执行哪一个语句
break;
case condition:
break;
default:
循环语句(迭代语句)
for while do
对于那些没有明确的循环变量,或者循环变量的更新自然地出现在循环体中间事。更偏向于采用while语句而不是for语句。
尽量避免使用do语句
goto:利用goto跳进或者跳出到某一个快
break 跳出循环
contine跳出当前循环,进行下一次循环
- 尽可能使用标准库,而不是其他的库和“手工打造的代码”
- 避免过于复杂的表达式,如果对运算符优先级有疑问,加括号
- 避免显示类型转换(强制),若必须要做这样的转换,提倡使用特殊的强制运算发,而不是c风格的强制
- 避免goto和do语句
4. 函数
函数声明
返回值类型 函数名 (传入参数){};
extern void swap(int *,int *);
void swap(int *p,int *q)//传入两个int型的指针
{
int t=*p;
*p=*q;
*q=t;
}
一个没有声明void的函数都必须返回一个值(main函数除外),与此相反,void函数就不能返回值,返回值由返回语句return描述;
绝不能返回指向局部变量的指针,因为被指向的位置中内容的改变情况时无法预料的
形参、实参
- 形参是函数定义时引用,实参是实际定义的参数
- 正常将实参的值传入形参中时,实参的值不会被改变,如果要改变实参的值,用引用传递或者指针传递
#include <iostream>
#include<string>
using namespace std;
void swap01(int a,int b)//采用值传递
{
int t=a;
a=b;
b=t;
cout<<b<<endl;//此时函数内部完成交换
}
void swap02(int &a,int &b)//采用地址传递
{
int t=a;
a=b;
b=t;
cout<<b<<endl;//此时a和b的实参也完成了交换
}
int main()
{
int c=10;
int d=5;
swap01(c,d);
swap01(c,d);
cout<<"c的值为: "<<c<<endl;
cout<<"d的值为: "<<d<<endl;
//运行swap01后执行的结果依旧是c=10,d=5;
//运行swap02后执行的结果依旧是c=5,d=10;
return 0;
}
- 修改引用参数的函数将会使程序更难阅读,因此最好避免写这种函数。可以将有关的参数声明为const,以此指明这种参数仅仅是为了效率的原因,而不是想让调用函数能够修改对象的值
- 如果在一个引用参数的声明中没有const,就应该认为,这是想说明该参数将被修改
数组参数
如果将数组作为函数的参数,传递的就是到数组的首元素的指针
这也就意味着,对数组参数的某个元素的赋值,将会改变实际参数数组中那个元素的值。也就是说,数组不能按值的方式传递
这也就是意味着,数组参数的大小是不可用的。因此可以传递第二个参数,用它来刻画数组的大小
void computel(int *vec_ptr,int vec_size);
struct Vec{
int *ptr;
int size;
}
vector等类型可以用于代替内部的、低级的数组和指针等一类东西
静态变量 static
静态变量为函数提供了一种“存储器”,使我们不必去引进可能被其他函数访问或者破环的全局变量
重载函数
将同一个名字用于在不同类型上操作的函数的情况称为重载。
如:对于加法只存在一个名字+,却可以用于做整型、浮点型、和指针值的加法。print、sqrt等等也是这样子的
void print(int);
void print(const char*);
void print(double);
void print(long);
void print(char);
//返回值不同不能进行重载
void h(char c,int i,short s,float f)
{
print(c);//精准匹配,调用print(char)
print(i);
print(s);
print(f);
print('a');//准确匹配,调用print(char)
print(49);
print(0);
print("a");//准确匹配,调用print(const char*)
//加入const是表明我不想修改指针指向的值
}
重载解析与被考虑的函数声明顺序无关
宏
- 绝不应该去使用它,除非你不得不这样做
- 宏名字不能重载,而且宏预处理器不能处理递归调用
5. 命名空间和异常
命名空间
c++提供了一种机制,可以把相关的数据、函数等组织到一个独立的名字空间里,这些名字的其他使用将不会与之干扰,不会引起混乱。引用时名字::成员
名字空间是一种描述逻辑分组的机制。也就是说如果有一些声明按照某种准则在逻辑上属于同一个集团,就可以将它们放入同一个命名空间。
定义命名空间使用关键词namespace,后跟命名空间的名称
调用时名称::成员
使用using namespace指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称,将使用指定的命名空间中的名称
namespace Stack{ //命名空间
void push(char);
char pop();
}
//只是用using部分指令
#include <iostream>
using std::cout;//仅仅在用cout时不需要加命名空间,取余成员还是需要加命名空间
int main ()
{
cout << "std::endl is used with std!" << std::endl;
return 0;
}
一个命名空间的各个组成可以分散在多个文件中。
当一个模块使用另一个模块时,它不需要知道有关被用模块的所有东西,理想的情况是,一个模块的大部分细节都不为其使用者所知
异常
当一个程序时由一些相互分离的模块组成时,特别是当这些模块来自某些独立开发的库时,错误处理的工作就需要分成两个相互独立的部分
- 一方报告出那些无法在局部解决的错误
- 另一方处理那些在其他地方检查出的错误
异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。
异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw。
- throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
- catch:在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
- try: try块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
#include <iostream>
using namespace std;
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);//当除数为0时,抛出一个异常
}
int main ()
{
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
cout << z << endl;
}catch (const char* msg) {
cerr << msg << endl;
}
return 0;
}
6. 源文件和程序
#include机制是一种正文操作的概念,用于将源程序片段收集到一起,形成一个提供给编译的文件。
#include<iostream>//来自标准库
#include"myheader.h"//来自用户
程序终止
- 通过main()函数返回
- 通过调用exit() //所有已经被构造起来的静态对象的析构函数都将被调用。这意味着exit()并不立即终止程序,在析构函数里调用exit()有可能导致无穷递归
- void exit();和main()的返回值一样,exit()的参数也将作为程序的值返回给系统,用0返回指明程序调用成功
- 通过调用abort()//析构函数不会被调用
- 通过抛出一个未被捕捉的异常
抽象机制
7. 类
类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法,类中的数据和方法称为类的成员。函数在一个类中被称为类的成员。
public | 类内和类外都可以访问 |
private | 类外不可访问(默认情况下是private) |
protected | 类外不可访问,子类也无法继承 |
class和struct的区别是,class默认权限是私有,struct默认权限是公共
构造函数和析构函数
#include <iostream>
using namespace std;
class Line
{
public:
void setLength( double len );
double getLength( void );
Line(); // 这是构造函数,构造函数与类名相同
//Line(double len);//构造函数带参数,在创建对象时给对象赋初值
~Line();//析构函数:不会返回任何值,也不能带有任何参数,有助于在跳出程序前释放资源
private:
double length;//一般成员属性用作私有,成员行为用作公共
};
// 成员函数定义,包括构造函数
Line::Line(void)
{
//lenth=len;构造函数带参数的情况
cout << "Object is being created" << endl;
}
void Line::setLength( double len )
{
length = len;
}
double Line::getLength( void )
{
return length;
}
// 程序的主函数
int main( )
{
Line line;
// 设置长度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() <<endl;
return 0;
}
class Teacher
{
public:
Teacher(int age) :age(age){};//构造函数后面跟着一个冒号,是为了初始化列表
~Teacher(){};
public:
int age;
};
友元函数
类的友元函数是定义在类外部,但有权访问类的所有私有和保护成员。尽管友元函数的原型在类的定义中出现过,但是友元函数并不是成员函数。
#include <iostream>
using namespace std;
class Box
{
double width;
public:
friend void printWidth( Box box );//声明友元函数,并不是成员函数
void setWidth( double wid );
};
// 成员函数定义
void Box::setWidth( double wid )
{
width = wid;
}
// 请注意:printWidth() 不是任何类的成员函数
void printWidth( Box box )
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box.width <<endl;
}
// 程序的主函数
int main( )
{
Box box;
// 使用成员函数设置宽度
box.setWidth(10.0);
// 使用友元函数输出宽度
printWidth( box );
return 0;
}
this指针
this指针是所有成员函数的隐含参数。友元函数没有this指针,因为友元函数不是类的成员,只有成员函数才有this指针。
this指针指向的是自己这一个函数的对象
#include <iostream>
using namespace std;
class Box
{
public:
// 构造函数定义
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}//析构函数带参数,初始默认直接赋值
double Volume()
{
return length * breadth * height;
}
int compare(Box box)
{
return this->Volume() > box.Volume();//this指针指向的是这个函数的
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
int main(void)
{
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
if(Box1.compare(Box2))//this指针指向的是Box1,传入的是Box2
{
cout << "Box2 is smaller than Box1" <<endl;
}
else
{
cout << "Box2 is equal to or larger than Box1" <<endl;
}
return 0;
}
//输出结果:Box2 is equal to or larger than Box1
8. 运算符重载
c++允许在同一个作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载,
运算符重载,可以重新定义c++大部分的内置运算符-
#include <iostream>
using namespace std;
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}
void setBreadth( double bre )
{
breadth = bre;
}
void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator+(const Box& b)//重载运算符
{//返回值类型 operator符号(参数类型)
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// 程序的主函数
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 把体积存储在该变量中
// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;
//类相加是无法做到的,这里用运算符重载达成类相加的目的
// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0;
}
9. 继承和多态
继承
// 基类
class Animal {
// eat() 函数
// sleep() 函数
};
//派生类
class Dog : public Animal {//class 子类名 : 继承方式 父类名
// bark() 函数
};
访问 | public | protected | private |
---|---|---|---|
同一个类 | yes | yes | yes |
派生类 | yes | yes | no |
外部的类 | yes | no | no |
我们几乎不使用protected和private继承,通常都是使用public继承
公共继承public | 公共-公共、保护-保护、私有-私有 |
---|---|
保护继承(protected) | 公共-保护,私有-保护、保护-保护 |
私有继承(private) | 公共和保护—私有 |
多继承
每个基类之间用逗号分隔
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
多态
c++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不用的函数
多态的实现:子类中有父类中已经声明的函数,为了防止早绑定,要在父类的同名函数前加上关键字virtual
使用关键字virtual声明的函数也叫做虚函数
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
virtual int area()//这里如果不加virtual,就是早绑定,在调用area函数时,只会调用父类中的函数,而不会调用子类中的函数
{
cout << "Parent class area :" <<endl;
return 0;
}
//virtual int area()=0;
//纯虚函数,在子类中必须要重新写一遍
};
class Rectangle: public Shape{
public:
Rectangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape{
public:
Triangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// 程序的主函数
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// 存储矩形的地址
shape = &rec;
// 调用矩形的求面积函数 area
shape->area();
// 存储三角形的地址
shape = &tri;
// 调用三角形的求面积函数 area
shape->area();
return 0;
}
10. 模板(泛型编程)
函数模板
template <class T>//T是所使用数据类型的占位符,后面都可以用T来定义数据类型
ret-type func-name(parameter list)
{
//函数主体
}
//实例分析
#include <iostream>
#include <string>
using namespace std;
template <class T>
inline T const& Max (T const& a, T const& b)
{
return a < b ? b:a;
}
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
类模板
template<class T>
class class-name
{
//
}
11. 动态内存
- 栈:在函数内部声明的所有变量都将占用栈内存
- 堆:程序中未使用的内存,在程序运行时可用于动态分配内存
在c++中,可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间的地址,这种运算符即new运算符。由于返回的是一个地址,所以需要一个指针去接收
由new分配的内存,由delete来删除
int *p=NULL;//要创建一个指针去接收new新建的对象的地址
p=new data;
*p=2;//为分配的地址存储值
delete p;//不用的时候用delete释放掉
//为数组分配内存
char *p=NULL;
p=new char[20];
delete []p;
//二维数组
int **array;//指向每一行的指针
array=new int*[m];//创建m行数组
for(int i=0;i<m;i++)
array[i]=new int[n];//创建每一行的n个位置
//释放
for(int i=0;i<m;i++)
delete []array[i];//
delete []array;
12. 文件和流
在c++中进行文件处理,要在源代码文件中包含头文件
数据类型 | 描述 |
---|---|
ofstream | 表示输出文件流,用于创建文件并向文件写入信息 |
ifstream | 表示输入文件流,用于从文件读取信息 |
fstream | 表示文件流,能读能写 |
下面是 open() 函数的标准语法,open() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。
void open(const char *filename, ios::openmode mode);
open()成员函数第一个参数指定要打开的文件名称和位置,第二个参数定义文件被打开的方式
模式标志 | 描述 |
---|---|
iOS::app | 追加模式,所有写入都追加到文件末尾 |
iOS::ate | 文件打开后定位到文件末尾 |
iOS::out | 打开文件用于写入 |
iOS::in | 打开文件用于读取 |
iOS::trunc | 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为0 |
ofstream outfile;
outfile.open("file.dat",ios::out | ios::trunc);
//以写入模式打开文件,并希望截断文件,以防止文件已经存在
ofstream outfile;
outfile.open("file.dat",ios::out | ios::in);
//打开文件进行读写
关闭文件 void close() close()函数是fstream、ifstream、oftream对象的一个成员。
写入文件
在 C++ 编程中,我们使用流插入运算符( << )向文件写入信息,就像使用该运算符输出信息到屏幕上一样。唯一不同的是,在这里您使用的是 ofstream 或 fstream 对象,而不是 cout 对象。
读取文件
在 C++ 编程中,我们使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。唯一不同的是,在这里您使用的是 ifstream 或 fstream 对象,而不是 cin 对象。
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
char data[100];
// 以写模式打开文件
ofstream outfile;//创建一个可以编辑文件的对象
outfile.open("afile.dat");//打开这个文件,没有目录表示和源代码在一个目录下
cout << "Writing to the file" << endl;
cout << "Enter your name: ";
cin.getline(data, 100);//把用户输入的数据用一个字符数组存放起来
// 向文件写入用户输入的数据
outfile << data << endl;//直接用左移运算符把数据写入文件中
cout << "Enter your age: ";
cin >> data;
cin.ignore();
// 再次向文件写入用户输入的数据
outfile << data << endl;
// 关闭打开的文件
outfile.close();
// 以读模式打开文件
ifstream infile;
infile.open("afile.dat");
cout << "Reading from the file" << endl;
infile >> data;
// 在屏幕上写入数据
cout << data << endl;
// 再次从文件读取数据,并显示它
infile >> data;
cout << data << endl;
// 关闭打开的文件
infile.close();
return 0;
}