目录
一、C++初探:
进入C++, C++就开始有面向对象,有类
// C++的标准输出,<<运算符 操作符 重载
std::cout << "Hello, World!" << std::endl;
1.C语言与C++语言兼容:
方式一:
main 上面的代码
/**
*
* C语言编译后的方法标记:test
* C++编译后的方法标记:Z4testii
* C语言 和 C++ 语言编译出来的 方法标记不同,是无法完成兼容 C++ 使用 C语言的
*
* extern ”C“ 编译器 这部分的代码,以C的形式来编译,就可以对上了
* 如果不使用extern ”C“,那么Test.c的方法就会以C++的形式编译,成了Z4testii,并不是test,就找不到了
*/
extern "C" {
#include "Test.h"
}
2.引用类型:
main的上面
/**
* TODO 为了学习引用类型
*/
void changeMethod(int& change) {
change = 6868;
}
main里面
// TODO C++ 中有一个 新型的类型 叫做 “引用类型”
int age = 99;
/*
* int& 就是C++中的引用类型
* 下面这句话的意思是:把age 这个内存地址 取了一个标记引用 就是 ageYin
*/
int& ageYin = age;
changeMethod(ageYin);
std::cout << "age:" << age << std::endl;
std::cout << "age内存地址:" << &age << std::endl;
std::cout << "ageYin:" << ageYin << std::endl;
std::cout << "ageYin内存地址:" << &ageYin << std::endl;
3.字符串
#include <string> // C++ 中的字符串 注意:在iostream中就有string,配合 std 命名空间才能使用
// TODO 字符串
// test01();
char string01[] = {'J','A','V','A', '\0'};
std::cout << "c++ item:" << string01 << std::endl;
char * string02 = "PHP";
std::cout << "c++ item:" << string02 << std::endl;
// string std 字符串里面的函数 strcpy
char buffer[20];
char * charValue = "Kevin C++";
std::strcpy(buffer, charValue);
std::cout << "buffer的值是:" << charValue << std::endl;
std::string str1 = "谢晓峰";
std::string str2 = "乔峰";
std::string str3("狄云");
std::string str4("步惊云");
std::string *str5 = new string; // new 代表申请内存
*str5 = "丁典";
cout << "str1:" << str1 << "str2:" << str2 << "str3:" << str3 << "str4" << str4 << "str5" << *str5 << endl;
delete str5; // 记得:一旦申请了内存,一定要释放内存
/**
* 申请 与 释放 对应表
* malloc ---> free
* new ---> delete
* new 数组 ---> delete []
*/
// 拼接字符串
// 为什么能够 + ,这就涉及到 操作符重载,因为string这个类,它实现了 + 操作符重载,所以就能够拼接字符串
string str6 = str1 + " " + str3;
cout << "str6:" << str6 << endl;
str6.append("结尾...");
cout << "str6:" << str6 << endl;
// 这样直接输出, 在Java中 如果输出的是对象,会默调用该对象的toString()方法
string *str7 = new string;
*str7 = "九阳神功";
cout << str7->c_str() /*+ str7->size() + str7->empty()*/ << endl;
// (*str7).c_str();
// str7->c_str();
4.命名空间:
::域作用符
命名空间是C++才有的 在C中是没有的
main上面的:
using namespace std; // 使用std命名空间
// TODO 为了学习命名空间
namespace KevinNameSpace { // 定义命名空间
void kevinMethod() {
cout << "kevinMethod...." << endl;
}
};
// 使用KevinNameSpace命名空间
using namespace KevinNameSpace;
namespace PersonSpace {
// 命名空间是可以内嵌的
namespace StudentSpace { // 定义命名空间
void showStudentName() {
cout << "学生的名字是:杜子腾" << endl;
}
}
}
using namespace PersonSpace::StudentSpace; // 使用命名空间
using namespace PersonSpace; // 使用命名空间
/**
* 命名空间 和 include 对比:
* 命名空间类似于 Java中的 import 导入就可以取调用里面的 函数 ... 操作
* include 是文本替换,属于预处理器操作阶段,进行文本替换的操作来处理的,和命名空间 截然不同
*/
int value09 = 9999999;
main里面的
// 使用命名空间
// KevinNameSpace::kevinMethod(); // 如果没有使用KevinNameSpace命名空间,就需要使用域作用符
kevinMethod(); // 使用了KevinNameSpace命名空间,就不需要使用域作用符
PersonSpace::StudentSpace::showStudentName(); // 如果没有使用 命名空间
showStudentName(); // 使用了,就可以直接调用,不需要域作用符
StudentSpace::showStudentName(); // 使用了:using namespace PersonSpace;
// 域作用符 的其他用法
int value09 = 9000000;
cout << value09 << endl;
cout << ::value09 << endl; // 可以使用到 main方法上面的value09
5.类的定义与使用:
Student.h
#ifndef NDK04_CODE_STUDENT_H
#define NDK04_CODE_STUDENT_H
#endif //NDK04_CODE_STUDENT_H
#pragma once // 是在预处理器 只保证引入一次,但是可能很多的编译器不支持,所以就需要以下的这种写法
#include <iostream>
#ifndef STUDENT_H // 如果没有定义这样一个宏,
#define STUDENT_H // 那么就定义这个宏
class Student
{
// 默认是 private 私有的
int age;
public:
Student(); // 构造函数
Student(int age, int age2, int age3); // 构造函数
Student(int age, int age2); // 构造函数
~Student(); // 析构函数
private:
int age2;
protected:
int age3;
private:
int privT01;
int privT02;
int privT03;
public:
int * value01;
char * value02;
void setAge(int age);
/**
* 常量函数
* 在函数的后面 增加了 const 就是属于了常量函数
* 常量函数 不允许修改类中的成员了
*/
void setAge2(int age2) const ;
void setAge3(int age3);
void setPrivT01(int privT01);
// 声明一个友元函数
friend void updateField(Student *);
// 声明一个友元类 Person,此Person就能够操作Student中的私有 不可访问的 成员变量了
friend class Person;
};
// 此类想要能够访问Student类,此类需要成为友元类
class Person {
void updateStudentMethod(Student * student) {
student->privT01 = 11111111;
student->privT02 = 21111111;
(*student).privT03 = 31111111;
}
};
#endif
Student.cpp
#include "Student.h"
using namespace std;
Student::Student() { // 对应头文件中 构造函数的实现
cout << "构造函数执行了..." << endl;
}
Student::Student(int age, int age2, int age3) {
this->age = age;
this->age2 = age2;
this->age3 = age3;
cout << "3参 有参构造函数执行了 值是 age:" << age << " age2:" << age2 << " age3:" << age3 << endl;
this->value02 = (char *) malloc(10 * sizeof(char));
}
Student::Student(int age, int age2) :age(age), age2(age2) {
cout << "2参 有参构造函数执行了 值是 age:" << age << " age2:" << age2 << endl;
}
void Student::setAge(int age) {
this->age = age;
this->value01 = (int *) malloc(10 * sizeof(int));
}
void Student::setAge2(int age2) const {
// 常量函数,不能修改类中的成员变量了
// this->age2 = age2;
}
void Student::setAge3(int age3) {
this->age3 = age3;
}
void Student::setPrivT01(int privT01) {
this->privT01 = privT01;
}
/**
* 这个析构函数,可以完成一些收尾工作
* 例如:在构造方法中,使用了malloc,可以在析构函数中去free
*/
Student::~Student() { // 对应头文件中,析构函数的实现
cout << "析构函数执行了..." << endl;
// 让析构函数有一个责任:就是可以去释放当前Student类中,在堆中开辟申请的内存空间
free(this->value01);
this->value01 = NULL;
free(value02);
this->value02 = 0;
}
6.单例模式
头文件:MyInstance.h
#include <iostream>
class MyInstance {
private:
static MyInstance * instance;
MyInstance();
~MyInstance();
public:
static MyInstance * getInstance();
void show();
void show2();
// 给外界提供释放单例的
void unInstance();
};
MyInstance.cpp
#include "MyInstance.h"
#include "mylog.h"
// #define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
/**
* 注意:把MyInstance * 理解成返回值
*/
MyInstance * MyInstance::instance;
MyInstance::MyInstance() {
// LOGD("我是无参构造函数");
// __android_log_print(ANDROID_LOG_DEBUG, "TAG", "我是无参构造函数");
}
MyInstance::~MyInstance() {
LOGD("此单例模式被释放了...");
}
MyInstance * MyInstance::getInstance() {
// 伪代码
/*if (instance == null) {
锁
if(instance == null) {
new ...
}
}*/
// C++11之后,内部会自动保证,所有static成员变量,线程的安全问题,内部已经处理好了,我们不用关心了
if(!instance) { // instance == null
instance = new MyInstance();
}
return instance;
}
void MyInstance::show() {
LOGD("show");
}
void MyInstance::show2() {
LOGD("show2");
}
// 释放单例
void MyInstance::unInstance() {
if (instance) {
delete instance;
instance = nullptr;
}
}
7.运算符重载
第一种方法:重载运算符+,类中定义。
class MyOperate {
public:
MyOperate(int i, int j) : i(i), j(j) {}
MyOperate() {};
public:
int i;
int j;
public: MyOperate operator + (MyOperate &myOperate) {
MyOperate temp;
temp.i = myOperate.i + this->i;
temp.j = myOperate.j + this->j;
return temp;
}
};
使用:
MyOperate myOperate1(1,3);
MyOperate myOperate2(4,6);
MyOperate andtemp = myOperate1+myOperate2;
第二种方法: 类外定义
// TODO 另外一种运算符重载
class MyOperator2
{
public:
int count;
};
MyOperator2 operator + (MyOperator2 m1, MyOperator2 m2)
{
MyOperator2 temp;
temp.count = m1.count + m2.count;
return temp;
}
使用和第一种方法一样
特殊字符的重载,可用于监控创建对象和回收对象。
// TODO 特殊的一些操作符
void * operator new (size_t size) {
LOGD("谁又new了,大小是:%d", size);
return malloc(size);
}
void operator delete(void * p) {
LOGD("谁delete了,内存地址是:%#x", p);
}
下面是可重载的运算符列表:
双目算术运算符 | + (加),-(减),*(乘),/(除),% (取模) |
关系运算符 | ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于) |
逻辑运算符 | ||(逻辑或),&&(逻辑与),!(逻辑非) |
单目运算符 | + (正),-(负),*(指针),&(取地址) |
自增自减运算符 | ++(自增),--(自减) |
位运算符 | | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移) |
赋值运算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
空间申请与释放 | new, delete, new[ ] , delete[] |
其他运算符 | ()(函数调用),->(成员访问),,(逗号),[](下标) |
下面是不可重载的运算符列表:
- .:成员访问运算符
- .*, ->*:成员指针访问运算符
- :::域运算符
- sizeof:长度运算符
- ?::条件运算符
- #: 预处理符号
详解实例参见:C++ 重载运算符和重载函数 | 菜鸟教程
8.继承
基类
关键字:virtual 定义虚函数。
class Person
{
private:
int age;
char sex;
public:
char * name = "Kevin";
//普通函数
void show01() {
LOGD("fuShow run ...");
}
// 虚函数
// Parent things= new Chlid();
//这种方式的对象会 执行子类的实现。
//普通函数则调用父类的实现
virtual void show04() {
LOGD("fuShow4 run ...");
}
// 纯虚函数 == Java的抽象方法
//子类必须实现该方法
virtual void show05() = 0;// 0 == NULL
};
子类
// 子类
// 如果是 : Person 就 == private Person
// private Person 子类自力更生,永远不用父类的成员(只是建立子父关系)
class Workder : public Person, protected Person2, private Person3, Person4
{
public:
void show01() {
LOGD("ziShow run ...");
}
void show04() {
LOGD("ziShow4 run ...");
}
void show05() {
LOGD("ziShow5 run ...");
}
};
继承的三种方式:
9.虚函数/纯虚函数
关键字:virtual 定义虚函数。
虚函数:
纯虚函数:声明如下: virtual void funtion1()=0;虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口
10.模板编程
对比学习Java中的泛型。
定义
// 函数模板 == Java泛型方法
template <class T>
T max(T number1, T number2) {
return number1 > number2 ? number1 : number2;
}
// 类模板 == Java泛型类
template <class Q, class P>
class TestClass {
public:
P getP(P p) {
return p;
}
Q getQ(Q q) {
return q;
}
};
简单使用
// 使用函数模板
max(1000000, 2000000);
max('M', 'w');
max("你好", "我好");
max("步惊云", "乔峰");
max(3466436.4564, 34645644.5346);
// 使用类模板
TestClass<long , string> testClass;
string pValue = testClass.getP("许三多");
long qValue = testClass.getQ(9999999);
10.类型转换
// 静态类型的转换 (涉及的是指针类型相关的转换操作)
// 静态多态--编译时期
ZiClass *ziClass = static_cast<ZiClass*>(fuClass);
动态类型的转换 -- 运行时期
ZiClass *ziClass = dynamic_cast<ZiClass *>(fuClass);
- 基本数据类型转换
// TODO 类型转换
// C++的新式转换 转换操作符
// const_cast:主要是 修改类型的const
const char *c1 = "#x001241";
char* c2 = const_cast<char*>(c1);
char * c3 = "#x581545";
const char * c4 = const_cast<const char*>(c3);
- 类类型转换
// TODO 为了学习转换 class Person { public: virtual void show() { cout << "父类 Person show" << endl; } }; class Student : public Person { public: void show() { cout << "子类 Student show" << endl; } };
// C++的静态转换 转换操作符 // static_cast: // 1.基础类型的互转,例如:int转float,int转unsigned init 等操作 // 2.指针与void之间的互转,例如:float* 转 void* , 函数指针 转 void* 等操作 // ... Person * person = new Person; Student * student = static_cast<Student*>(person); student->show(); delete person; // 回收的规则,一定是 谁new了,我就回收谁*/ // 如果不想使用 以上类型的 类型转换操作符,也可以使用 “强制类型转换”
11.异常
异常函数的定义/ 自定义异常
// TODO 为了学习异常
void exceptMethod01() {
throw "我报错了,9527...";
}
void exceptMethod02() {
throw exception("我报废了,9687.。。");
}
// 自定义异常
class CustomExceptionClass : public exception
{
public:
virtual char const* what() const
{
return "CustomExceptionClass 自定义异常";
}
};
void exceptMethod03() {
CustomExceptionClass c;
throw c;
}
// 随便自定义一个类,作为异常类,都是可以的,抛出一个对象作为异常
class Dog
{
public:
char * name;
void showName() {
cout << "捕获到exceptMethod04函数发生了异常: shouName:" << this->name << endl;
}
};
void exceptMethod04() {
Dog d;
d.name = "阿黄";
throw d;
}
异常函数调用
// TODO 异常
try {
exceptMethod01();
} catch (const char* exceptionMessage) {
cout << "捕获到exceptMethod01函数发生了异常,异常详情:" << exceptionMessage << endl;
}
try {
exceptMethod02();
} catch (exception &e) {
cout << "捕获到exceptMethod02函数发生了异常,异常的信息:" << e.what() << endl;
}
try {
exceptMethod03();
} catch (CustomExceptionClass &exceptionClass) {
cout << "捕获到exceptMethod03函数发生了异常,信息是:" << exceptionClass.what() << endl;
}
try {
exceptMethod04();
}catch (Dog &d) {
d.showName();
}
12.常量函数
摘录:https://www.cnblogs.com/xinxue/p/5405362.html
常量成员函数 (const member function), 可读取类中的数据成员,但不能修改
1.1 const 关键字
参数列表后,加 const 关键字,声明为常量成员函数,表明其不被允许修改类的数据成员
下面的类,以年、月、日的形式来表示日期 (注意:年月日的声明顺序)
class Date {
public:
int GetYear() const { return y_; }int GetMonth() const { return m_; }
int GetDay() const { return d_; }
void AddYear(int n); // add n years
private:
int y_, m_, d_;
};
1) 如果常量成员函数,企图修改类的数据成员,则编译器会报错
// error : attempt to change member value in const function
int Date::GetYear() const
{
return ++y_;
}
2) 如果在类外面,“定义” 常量成员函数 ( “定义” = 实现,即 implementation),则 const 关键字不可省略
// error : const missing in member function type
int Date::GetYear()
{
return y_;
}
1.2 陷阱
类中成员变量的声明顺序,决定了成员变量的初始化顺序。假设 Date 类中的构造函数为:
public:
Date() : y_(2016), m_(9), d_(22) {}
此时,类中的成员函数,在类中的声明顺序 = 构造函数初始化列表顺序,故 y_, m_, d_ 都能被顺利的初始化为对应的值。
而当成员变量,在类中的声明顺序 ≠ 构造函数初始化列表顺序 时,
public:
Date() : y_(2016), d_(22), m_(d_-13) {}
根据成员变量的声明顺序,y_ 首先被初始化为 2016,然后再初始化 m_,但由于 d_ 并未被初始化,所以 m_ 的值是随机的,最后初始化 d_ 为 22
这是因为,类的成员变量在初始化时,其初始化的顺序只与声明顺序有关,而与在初始化列表中的顺序无关。
13.vector容器
序列式容器 vector:
导入:
#include <vector> // // C++ 容器中提供的
api的调用
// C++ 中容器,分为两种类型
// 1.序列式容器:元素的排序关系,和元素本身没有任何关系,是我们在添加的时候导致的顺序导致的排序
// vector priority_queue
vector<int> vec01(1); // 声明一个元素的空间
vector<string> vec02(100, "杜子腾"); // 声明100个元素空间,值都是=“杜子腾”
vector<string> vec03;
// 添加元素
vec03.push_back("杜子腾");
vec03.push_back("戴乐静");
vec03.push_back("史珍香");
// 删除元素
vec03.pop_back(); // 删除最新的,最后添加的元素,删除“史珍香”
//插入指定元素
vec03.insert(*allName.end() - 1, "ff");
//删除指定元素
vec03.erase(*vec03.begin()+1);
// 获取元素
string value = vec03.at(0);
value = vec03[1];
cout << value << endl;
// 清空元素
vec03.clear();
// vec03.erase(vec03.begin(), vec03.end());
// 是否被清空了
if (vec03.empty()) {
cout << "元素被清空" << endl;
} else {
cout << "元素没有被清空" << endl;
}
// 容器有很严重的问题
// 此容器,占用的内存空间,是只增不减的
cout << "此Vector容器,占用内存空间是:" << vec03.capacity() << endl;
// 全局问题演示
test01();
return 0;
注意clear()函数的坑
容器被清空之后vec03.capacity()还是有占位的,且只增不减。正常在栈中实例化的,弹栈后即可回收,但如果有全局的vector,则需想办法回收
// 想办法让容器有问题, 全局
vector<string> allName;
void test01() {
allName.push_back("1111");
allName.push_back("2222");
allName.push_back("3333");
allName.clear(); // 清空 内存空间 还是占用的 怎么办?
// 替换的方式:来解决此问题
vector<string> tempVector; // 定义临时容器目的:就是为了解决 、 替换全局容器,让全局容器不占用内存空间
tempVector.swap(allName); // 把全局的 全部移动 给临时 == 把全局的给回收了
} // 函数一弹栈 tempVector给回收了,就保证了,全局和临时全部回收完毕
14.priority_queue:优先级队列
#include <queue> // C++ 容器中提供的
传统方式
// 优先级队列 是在vector之上实现的,所以只能写vector<T>
priority_queue<int> priorityQueue;
priorityQueue.push(6);
priorityQueue.push(9);
priorityQueue.push(1);
// 值最大的 在第零个元素 也就是 top
cout << "priority_queue.top():" << priorityQueue.top() << endl;
// 调整 队列 下面这句话的意思就是,优先级队列是基于vector来实现的
priority_queue<int> priorityQueue2(int, vector<int>, greater<int>);
// priority_queue<int> priorityQueue2(int, vector<int>, less<int>);
// less:代表最大的元素在最前面
// greater:代表最小的元素在最前面
自定义方式
定义:
// TODO 为了学习优先级队列 priority_queue
class MyType
{
public:
int count;
MyType(int count) {
this->count = count;
}
};
// 自定义排序规则,才能给 MyType这个类,进行排序
struct MyTypeLess { // functor for operator<
// C++ 在结构体可以写函数
constexpr bool operator()(const MyType& _Left, const MyType& _Right) const {
return _Left.count < _Right.count;
}
};
引用:
// 由于此优先级队列,不知道如何给这个MyType类排序,而出现的错误
priority_queue<MyType, vector<MyType>, MyTypeLess> pqMyType;
pqMyType.push(MyType(1));
pqMyType.push(MyType(9999992));
pqMyType.push(MyType(3));
cout << "pqMyType.top():" << pqMyType.top().count << endl;
15.关联式容器 set
#include <set>
// ---- 关联式容器
// 通过一个关键字 来保存 和 访问 元素的 例如:Java中的 map set 都是关联式容器
set<int> set1 = {1,2,3,4,5};
set1.insert(999);
set1.insert(888);
set1.insert(777);
set1.insert(1); // 重复的元素添加不进去,因为set不允许 添加重复的元素
set1.insert(2); // 重复的元素添加不进去,因为set不允许 添加重复的元素
set1.insert(3); // 重复的元素添加不进去,因为set不允许 添加重复的元素
cout << "set1.size:" << set1.size() << endl;
// 删除元素
set1.erase(1);
pair<set<int>::iterator, bool> pair1 = set1.insert(1900000);
// 使用迭代器
set<int>::iterator beginResult = set1.begin(); // 指向容器中 第零个元素
set<int>::iterator endResult = set1.end(); // 指向容器中,最后一个 的下一个元素
cout << "beginResult:" << *beginResult << endl;
// 遍历set
for (; beginResult != set1.end() ; beginResult++) {
cout << "遍历set it:" << *beginResult << endl;
}
// 遍历vector
vector<string> vectorStr;
vectorStr.push_back("11");
vectorStr.push_back("22");
vectorStr.push_back("33");
vectorStr.push_back("44");
vectorStr.push_back("55");
vectorStr.push_back("66");
vector<string> :: iterator it = vectorStr.begin();
for (; it < vectorStr.end() ; it ++) {
cout << "遍历vector:" << *it << endl;
}
// -----
// map
map<int, string> map1;
map<int, string> map2 = { {1, "a"}, {2, "b"} }; // 不能有重复的元素和set一样
map2[2] = "bbb";
16.文件流
导入库
#include <iostream>
#include <ostream> // 输出
#include <istream> // 输入
#include <fstream>
C语言的文件流操作:
// TODO 文件流
// 文本的形式 写入
FILE* file1 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file.txt", "w"); // w:代表可写
// 在Windows上 文件格式是 GB2312的,在Mac上有乱码的
fprintf(file1, "今天是%d号。", 11);
fclose(file1); // 一定要关闭,和Java中的一样
// 文本的形式 读取文件
FILE* file2 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file.txt", "r"); // r:代表可读
char buffer[1024]; // 最大可以读取1023个字节,+ /0
fscanf(file2, "%s", buffer); // 如果遇到,空格,就直接返回了 结束读取
cout << "文件的内容是:" << buffer << endl;
fclose(file2);
// // 如果遇到,空格,就直接返回了 结束读取, 所以需要 循环读取
FILE* file3 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file2.txt", "r"); // r:代表可读
char buffer2[1024]; // 最大可以读取1023个字节,+ /0
while(!feof(file3)) {
fscanf(file3, "%s", buffer2);
cout << "文件的内容是:" << buffer2 << endl;
}
fclose(file3);
// 遇到 换行,/0 都会结束读取, 读取1024个字节
FILE* file4 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file2.txt", "r"); // r:代表可读
char buffer3[1025]; // + /0
fgets(buffer3, 1024, file4); // 读取1024个字节,这种很明确
cout << "file4:" << buffer3 << endl;
fclose(file4);
C++操作文件流:
char * file = "D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file3.txt";
// 写入
char data[200];
ofstream outFile; // 以写的模式去打开文件
outFile.open(file);
// 捕获用户在控制台输入信息
cout << "请您输入您要保存的信息:" << endl;
cin >> data; // 接收终端的输入信息,赋值给 data
// 把数据data 写入到文件中去
outFile << data << endl;
// 关闭上面打开的文件
outFile.close();
// -- 读取
char myData[200];
cout << "开始 自动的去读取 刚刚保存到文件里面的内容...." << endl;
ifstream ifstreamVar;
ifstreamVar.open(file);
ifstreamVar >> myData;
cout << myData << endl;
// 关闭
ifstreamVar.close();