最全C++阶段总结第三部分——八千字面向对象总结。三期C,2024年最新阿里大牛教你自己写C C++框架

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

test();
system("pause");
return 0;

}


#### 1.3.4const修饰成员函数


**常函数:**


* 成员函数后加const后我们称为这个函数为常函数  (void change\_2() const)
* 常函数内不可修改成员属性
* 成员函数声明时加关键字mutable后,在常函数中依然可以修改(mutable int b;)


**常对象:**


* 声明对象前加const称该对象为常对象(const A q;)
* 常对象只能调用常函数



#include
using namespace std;

class A
{
public:
void change_1()
{
a = 100;
b = 100;
}

//在成员函数后面加const,修饰的是this指针,让指针指向的值也不可以修改
void change_2() const      //相当于 const A* const this
{
	//a = 100;     //不可以修改
	b = 100;    //特殊变量,可以修改
}

int a;
mutable int b;    //特殊变量,即使在常函数中也可以修改

};

void test()
{
A p;
p.a = 100;
p.b = 100;
p.change_1();
p.change_2();
}

void test2()
{
const A q;
//q.a = 100; //常对象不能修改普通值
q.b = 100;
//q.change_1(); //错误,常对象只能调用常函数,因为普通成员函数可以修改属性
q.change_2();
}

int main()
{
test();
system(“pause”);
return 0;
}


### 1.4友元函数


友元的关键字:**friend**


三种实现形式:


* 全局函数做友元


即:当全局函数中的对象想要访问类中的私有属性时,需要将该全区函数在类中加以声明为friend类型



> 
> class Student  
>  {  
>      //此时全局函数show是类Student的好朋友,可以访问类的私有成员  
>      friend void show(Student &a);          //此时全局函数中的对象都可以访问类中的私有属性  
>  ........
> 
> 
> 



#include
using namespace std;
#include

class Student
{
friend void show(Student &a);

public:
Student()
{
age = 18;
name = “小明”;
}

string name;

private:
int age;
};

void show(Student &a)
{
cout << a.name << endl;
cout << a.age << endl;
}

int main()
{
Student m;
show(m);
system(“pause”);
return 0;
}


* 类做友元



> 
> class Class  
>  {  
>      ..........  
>  };
> 
> 
> class Student  
>  {  
>      friend class Class;  
>  .........
> 
> 
> 



#include
using namespace std;
#include

class Student;

class Class
{
public:
Class();
void show();
private:
Student *s;
};

class Student
{
friend class Class;
public:
Student()
{
age = 18;
name = “小明”;
}
string name;
private:
int age;
};
Class::Class()
{
s = new Student;
}

void Class::show()
{
cout << s->age << endl;
cout << s->name << endl;
}
int main()
{
Class a;
a.show();
system(“pause”);
return 0;


* 成员函数做友元



> 
> class Class  
>  {  
>      ..........  
>  };
> 
> 
> class Student  
>  {  
>         friend void Class::show();        //和类做友元类似,此处把类变成了函数  
>  .........
> 
> 
> 



#include
using namespace std;
#include

class Student;

class Class
{
public:
Class();
void show();
void show1();
private:
Student *s;
};

class Student
{
friend void Class::show();
public:
Student()
{
age = 18;
name = “小明”;
}
string name;
private:
int age;
};
Class::Class()
{
s = new Student;
}

void Class::show()
{
cout << s->age << endl; //类的友元函数,可以访问私有属性
cout << s->name << endl;
}
void Class::show1()
{
// cout << s->age << endl; //不能访问私有属性
cout << s->name << endl;
}
int main()
{
Class a;
a.show();
a.show1();
system(“pause”);
return 0;
}


### 1.5运算符重载


概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型


#### 1.5.1加号运算符重载


实现两个自定义数据类型相加的运算


和正常的相加思路类似,只不过这里需要引用其他的对象作为参数;



> 
>     //成员函数实现“+”运算符重载              p1=p2+p3;类似于:p1=p2.operator+(p3);  
>      Class operator+(const Class &p){  
>          Class q(0, 0);  
>          q.a = this->a + p.a;  
>          q.b = this->b + p.b;  
>          return q;  
>      }
> 
> 
> 



> 
> //全局函数实现“+”运算符重载             p1=p2+p3;类似于:p1=operator+(p2,p3);  
>  Class operator+(const Class &p1, const Class &p2){  
>      Class q(0,0);  
>      q.a = p1.a + p2.a;  
>      q.b = p1.b + p2.b;  
>      return q;  
>  }
> 
> 
> 



#include
using namespace std;
#include

class Class
{
public:
Class(int a, int b) :a(a), b(b){}
void show()
{
cout<<“a=”<< a << " b=" << b << endl;
}

//成员函数实现“+”运算符重载
Class operator+(const Class &p){
	Class q(0, 0);
	q.a = this->a + p.a;
	q.b = this->b + p.b;
	return q;
}

//private:
int a;
int b;
};

全局函数实现“+”运算符重载
//Class operator+(const Class &p1, const Class &p2){
// Class q(0,0);
// q.a = p1.a + p2.a;
// q.b = p1.b + p2.b;
// return q;
//}

int main()
{
Class a(10,10);
Class b(20, 30);
Class c(0, 0);
c= a + b;
c.show();
system(“pause”);
return 0;
}


#### 1.5.2运算符重载


作用:可以输出自定义数据类型



> 
> //只能用全局函数实现“<<”运算符重载  
>  ostream & operator<<(ostream &cout, const Class &p)    //本质operator<<(cout,p),简化cout<<p  
>  {  
>      cout << p.a << "    " << p.b << endl;  
>      return cout;             //此处返回cout的为了能够实现链式编程,可以多次返回输出  
>  }
> 
> 
> 



#include
using namespace std;
#include

class Class
{
public:
Class(int a, int b) :a(a), b(b){}

int a;
int b;

};

//如果利用成员函数重载 左移运算符 p.operator<<(cout) 简化版本 p<<cout;p在左侧错误

//只能用全局函数实现“<<”运算符重载
ostream & operator<<(ostream &cout, const Class &p) //本质operator<<(cout,p),简化cout<<p
{
cout << p.a << " " << p.b << endl;
return cout;
}

int main()
{
Class a(10,10);
cout << a<<endl;
system(“pause”);
return 0;
}


#### 1.5.3递增运算符重载


作用:通过重载递增运算符,实现自己的整型数据



> 
>     //重载前置++运算符  
>      Class &operator++()           //返回引用是为了一直对一个数据进行增值操作  
>      {  
>          a++;  
>          return \*this;  
>      }
> 
> 
>     //重载后置++运算符          //此时不能再使用链式操作了  
>      Class operator++(int)      //此处int作为占位符,用来区分前置还是后置  
>      {  
>          Class p = \*this;    //记录当前本身的值,然后让本身的值加1,但是返回的值还是以前的值  
>          a++;  
>          return p;  
>      }
> 
> 
> 前置返回的是一个引用,而后置返回的是结果是一个临时对象。因为后置的时候原来的对象已经被++改变了,所以需要一个新对象来保存改变之前的值。而前置用引用则是为了不产生临时变量,减少内存的消耗而已。
> 
> 
> 所以前置引用可以使用链式的方法,多次前置++,而后置不可以多次++;
> 
> 
> 



#include
using namespace std;
#include

class Class
{
friend ostream & operator<<(ostream &cout, const Class &p);

public:
Class(int a) :a(a){}

//重载前置++运算符
Class &operator++()           //返回引用是为了一直对一个数据进行增值操作
{
	a++;
	return *this;
}

//重载后置++运算符
Class operator++(int)      //此处int作为占位符,用来区分前置还是后置
{
	Class p = *this;    //记录当前本身的值,然后让本身的值加1,但是返回的值还是以前的值
	a++;
	return p;
}

private:
int a;
};

ostream & operator<<(ostream &cout, const Class &p)
{
cout << p.a << endl;
return cout;
}

int main()
{
Class a(10);
cout << ++(++a)<<endl;
cout << a << endl;
cout << a++ << endl;
cout << a << endl;
system(“pause”);
return 0;
}


#### 1.5.4赋值运算符重载


赋值运算符需要注意的地方就是当数据在堆区存储时,注意开辟新的空间以及及时释放空间



> 
>     void operator = (Class &p)  
>      {  
>          if (a != NULL)          //如果已经有值,需要先释放,再进行赋值  
>          {  
>              delete a;  
>              a = NULL;  
>          }  
>          //深拷贝  
>          a = new int(\*p.a);  
>      }
> 
> 
> 



#include
using namespace std;
#include

class Class
{
friend ostream & operator<<(ostream &cout, const Class &p);

public:
Class(int a){
this->a = new int(a);
}

void operator = (Class &p)
{
	if (a != NULL)
	{
		delete a;
		a = NULL;
	}
	//深拷贝
	a = new int(*p.a);
}

private:
int *a;
};

ostream & operator<<(ostream &cout, const Class &p)
{
cout << *p.a << endl;
return cout;
}

int main()
{
Class a(10);
Class b(20);
a = b;
cout << a << endl;
system(“pause”);
return 0;
}


#### 1.5.5关系运算符重载


作用:可以让两个自定义类型对象进行对比操作



> 
>     bool operator == (Class &p)             //相对比较简单,就简单传值,然后对比一下  
>      {  
>          if (this->a == a) {  
>              return true;  
>          }  
>          else {  
>              return false;  
>     } }
> 
> 
> 



#include
using namespace std;

class Class
{

public:
Class(int a){
this->a = a;
}

bool operator == (Class &p)
{
	if (this->a == a)
	{
		return true;
	}
	else
	{
		return false;
	}
}

private:
int a;
};

int main()
{
Class a(10);
Class b(20);
if (a == b)
{
cout << “两个数相等” << endl;
}
else
{
cout << “两个数不相等” << endl;
}
system(“pause”);
return 0;
}


#### 1.5.6函数调用运算符重载


* 函数调用运算符()也可以重载
* 由于重载后使用的方法非常像函数的调用,因此称为仿函数
* 仿函数没有固定的写法,非常灵活



> 
>     void operator()(string world)  
>      {  
>          cout << world << endl;  
>      }
> 
> 
> 



#include
using namespace std;
#include

class Class
{
public:
void operator()(string world)
{
cout << world << endl;
}
};

int main()
{
Class a;
a(“hells world”); //由于使用起来类似于函数调用,因此称为仿函数;非常灵活,没有固定写法

//此处为匿名函数对象
Class()("hello world");          //Class()代替了类似于a
system("pause");
return 0;

}


### 1.6继承


继承的好处:减少重复代码


继承语法:class A(子类) : 继承方式  B(父类)


子类也称为派生类;父类也称为基类


**派生类中的成员,包含两大部分:**


* 从基类继承过来的,表现其共性
* 自己增加的函数,体现其个性


#### 1.6.1 继承方式


一共有三种:


* 公有继承     (三种权限不变)
* 保护继承     (公+保->保,私不变)
* 私有继承     (公+保->私,私不变)
* 继承时,私有成员子类均不可访问,保护成员子类可以访问


下面这段代码,详细注释了各种情况下的访问和继承



#include
using namespace std;
#include

class Class
{
public:
int a;
protected:
int b;
private:
int c;
};

class sun1:public Class
{
void fun()
{
a = 10; //公有 不变
b = 10; //保护 不变
//c = 10; 错误,子类不可访问父类的私有成员
}
};
class sun2 :protected Class
{
void fun()
{
a = 10; //保护 变为
b = 10; //保护 不变
//c = 10; 错误,子类不可访问父类的私有成员
}
};
class sun3 :private Class
{
void fun()
{
a = 10; //私有 变为
b = 10; //私有 变为
//c = 10; 错误,子类不可访问父类的私有成员
}
};

void test()
{
sun1 p1;
p1.a = 10;
//p1.b = 20; //保护b不可访问
//p1.c = 30; //私有c不可访问

sun2 p2;
//p2.a = 10;      //保护a不可访问
//p2.b = 20;      //保护b不可访问
//p2.c = 30;      //私有c不可访问

sun3 p3;
//p3.a = 10;      //私有a不可访问
//p3.b = 20;      //私有b不可访问
//p3.c = 30;      //私有c不可访问

}
int main()
{
test();
system(“pause”);
return 0;
}


#### 1.6.2继承中的对象模型


继承规则:


* 父类中所有非静态成员属性都会被子类继承下去
* 父类中私有成员属性,是被编译器给隐藏了,因此是访问不到的,但是确实是继承下去了



> 
> class Class{  
>  public:   int a;  
>  protected:  int b;  
>  private:   int c;  
>  };  
>  class sun1 :public Class{  
>      int a;  
>  };                        //此时sun1定义出的对象大小就为16,继承的三个加上新增加的一个
> 
> 
> 


#### 1.6.3继承中构造和析构顺序


先构造父类,再构造子类,析构的顺序与构造的顺序相反(可以自己写代码实验)


#### 1.6.4继承同名成员处理方式


* 访问子类同名成员,直接访问即可
* 访问父类同名成员,需要加作用域



> 
>     sun p;  
>      cout << p.a << endl;  
>      cout << p.Base::a << endl;
> 
> 
> 


* 当子类与父类拥有同名成员函数,子类会隐藏父类中所有版本的同名成员函数
* 如果想访问父类中隐藏的同名成员函数,需要加父类的作用域



> 
>     p.change();    //子类中的成员函数  
>      //p.change(a);    //此处虽然是重载函数,但是只要子类父类发生重名,子类就会隐藏父类所有同名函数  
>      p.Base::change(9);     //父类中的带参成员函数  
>      p.Base::change();      //父类中的不带参成员函数
> 
> 
> 



#include
using namespace std;
#include

class Base{
public:
Base()
{
a = 10;
}
void change()
{
a = 100;
}
void change(int x)
{
a = x;
}
int a;
};
class sun:public Base{
public:
sun()
{
a = 20;
}
void change()
{
a = 200;
}
int a;
};

void test()
{
sun p;
//成员
cout << p.a << endl;
cout << p.Base::a << endl;

//成员函数
p.change();    //子类中的成员函数
//p.change(a);    //此处虽然是重载函数,但是只要子类父类发生重名,子类就会隐藏父类所有同名函数
p.Base::change(9);     //父类中的带参成员函数
p.Base::change();      //父类中的不带参成员函数

}
int main()
{
test();
system(“pause”);
return 0;
}


#### 1.6.5继承同名静态成员处理方式


静态成员和非静态成员出现同名,处理方式一致,只不过有两种访问方式


* 访问子类同名成员,直接访问即可
* 访问父类同名成员,需要加作用域



> 
>     cout << p.a << endl;  
>      cout << p.Base::a << endl;
> 
> 
>     cout << sun::a << endl;  
>      cout << sun::Base::a << endl;
> 
> 
> 


#### 1.6.6多继承语法


C++中允许**一个类继承多个类**


语法: class 子类 :继承方式 父类1,继承方式 父类2........


(实际开发中不建议)



> 
> class Base :public Base1, public Base2{}
> 
> 
> 



> 
> **当父类中出现同名成员,需要加作用域进行区分**
> 
> 
>     cout << p.a << endl;  
>      cout << p.Base1::a << endl;  
>      cout << p.Base2::a << endl;
> 
> 
> 



#include
using namespace std;
#include

class Base1{
public:
Base1()
{
a = 10;
}
int a;
};

class Base2{
public:
Base2()
{
a = 20;
}
int a;
};

class Base :public Base1, public Base2
{
public:
Base()
{
a = 30;
}

int a;

};

void test()
{
Base p;
cout << p.a << endl;
cout << p.Base1::a << endl;
cout << p.Base2::a << endl;
}

int main()
{
test();
system(“pause”);
return 0;
}


#### 1.6.7菱形继承


概念:


1. 两个派生类继承同一个基类
2. 又有某个类同时继承两个派生类
3. 这种继承称为菱形继承


![](https://img-blog.csdnimg.cn/2020070622274451.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2NDIzMTY2,size_16,color_FFFFFF,t_70)


如图所示:B1,B2继承A,C又继承B1,B2。


当出现这种零星继承时,如果两个父类拥有相同数据,需要加以作用域区分


这份数据我们知道,只需要一份就足够了,而菱形继承导致数据有两份,资源浪费。


**解决方法:**


* 利用虚继承 解决菱形继承的问题
* 继承之前加上关键字virtual变为虚继承
* A变为虚基类



> 
> class B1 :virtual public A{};  
>  class B2 :virtual public A{};
> 
> 
> 


### 1.7多态


#### 1.7.1多态的基本概念


多态分为两类:


* 静态多态:函数重载和运算符重载属于静态多态,复用函数名
* 动态多态:派生类和虚函数实现运行时多态


静态多态和动态多态的区别:


* 静态多态的函数地址早绑定-编译阶段确定函数地址
* 动态多态的函数地址晚绑定-运行阶段确定函数地址


地址早绑定的话,在编译阶段就确定了函数地址,因此函数就不会更改了,一直显示某一个


若要按要求执行,使得函数不提前绑定,就需要用到动态多态,即加上关键字"virtual",变成虚函数


动态多态满足的条件:


1. 有继承关系
2. 子类重写父类的虚函数          (重写:函数返回值类型,函数名,参数列表完全一致称为重写)


动态多态的使用:


1. 父类指针或者引用,执行子类对象



#include
using namespace std;
#include

class Base1{
public:
//虚函数
virtual void show()
{
cout << “Base1” << endl;
}
};

class Base2:public Base1
{
public:
void show()
{
cout << “Base2” << endl;
}
};

class Base3 :public Base1
{
public:
void show()
{
cout << “Base3” << endl;
}
};

void test(Base1 &p)
{
p.show();
}

int main()
{
Base1 p1;
Base2 p2;
Base3 p3;
test(p1);
test(p2);
test(p3);
system(“pause”);
return 0;
}


#### 1.7.2 纯虚函数和抽象类


因为在多态中,通常父类的虚函数实现毫无意义,通常都是调用子类重写的内容,因此可以将虚函数改为纯虚函数


语法:virtual 返回值类型 函数名(参数列表)=0


当类中有了纯虚函数,这个类也称为抽象类


**抽象类特点:**


* 无法实例化对象
* 子类必须重写抽象类中的纯虚函数,否则也属于抽象类



> 
> class Base1{  
>  public:  
>      //纯虚函数,所以此类也被称为抽象类  
>      virtual void show() = 0;  
>  };
> 
> 
> 则不能Base1 p; 因为Base1是抽象类,抽象类不能实例化对象。
> 
> 
> 



#include
using namespace std;
#include

class Base1{
public:
//纯虚函数,所以此类也被称为抽象类
virtual void show() = 0;
};

class Base2:public Base1
{
public:
//重写父类Base1中的show函数
void show(){ cout << “Base2”; }
};

class Base3 :public Base1
{

};
void test()
{
//Base1 p; //抽象类不能实例化对象
//Base3 p; //如果不重写抽象类中的纯虚函数,则子类也变成抽象类
Base2 p;
p.show();
}

int main()
{
test();
system(“pause”);
return 0;
}


#### 1.7.3虚析构和纯虚析构


多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码


解决方法:将父类中的析构函数改为**虚析类**或者**纯虚析构**


* 如果子类中没有堆区数据,可以不写虚析构或者纯虚函数


虚析类和纯虚析构共性:


* 可以解决父类指针释放子类对象
* 都需要有具体的函数实现


虚析类和纯虚析构区别:


* 如果是纯虚析构,该类属于抽象类,无法实例化对象


虚析构语法:


virtual ~类名(){}


纯虚析构语法:


virtual ~类名()=0



> 
>     //利用虚析构可以解决父类释放子类对象时堆区数据泄露的问题  
>      virtual ~Base1()  
>      {  
>         cout << "Base1的析构函数" << endl;  
>      }
> 
> 
>     //纯虚析构  需要声明也需要实现  
>      //有了纯虚析构,这个类也属于抽象类,无法实例化对象  
>      virtual ~Base1() = 0;
> 
> 
> 



#include
using namespace std;
#include

class Base1{
public:
Base1()
{
cout << “Base1的构造函数” << endl;
}

利用虚析构可以解决父类释放子类对象时堆区数据泄露的问题
//virtual ~Base1()
//{
//	cout << "Base1的析构函数" << endl;
//}

//纯虚析构  需要声明也需要实现
//有了纯虚析构,这个类也属于抽象类,无法实例化对象
virtual ~Base1() = 0;

};
Base1::~Base1()
{
cout << “Base1纯虚析构函数” << endl;
}

class Base2:public Base1
{
public:
Base2()
{
cout << “Base2的构造函数” << endl;
}
~Base2()
{
cout << “Base2的析构函数” << endl;
}
};

void test()
{
Base1 *p = new Base2;
//父类指针在析构时候,不会调用子类中析构函数,导致子类如果有堆区数据,会出现内存泄露
delete p;
}

int main()
{
test();
system(“pause”);
return 0;
}


## 2,文件操作


程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放


通过文件可以将数据持久化,需要包含的头文件<fstream>


文件类型分为两种:


* 文本文件:文件以文本的ASCLL码形式存储在计算机中
* 二进制文件:文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂他们


操作文件的三大类


* ofstream:写操作
* ifstream:读操作
* fstream:读写操作


### 2.1文本文件


#### 2.1.1写文件


**步骤:**



> 
> 1. 包含头文件:#include<fstream>
> 2. 创建流对象:ofstream test;
> 3. 打开文件:test.open("文件路径",打开方式);
> 4. 写数据:test<<"写入的数据";
> 5. 关闭文件:test.close();
> 
> 
> 



> 
>       //头文件  
>      ofstream test;  
>      test.open("test.txt", ios::out);  
>      test << "姓名:小明" << endl;  
>      test.close();
> 
> 
> 


**文件打开方式**




|  |  |
| --- | --- |
| 打开方式 | 解释 |
| ios::in | 为读文件而打开文件 |
| ios::out | 为写文件而打开文件 |
| ios::ate | 初始位置:文件尾 |
| ios::app | 追加方式写文件 |
| ios::trunc | 如果文件存在先删除,再创建 |
| ios::binary | 二进制方式 |


文件打开方式可以配合使用,利用” | ”操作符。


#### 2.1.2读文件


读文件与写文件步骤相似,但是读取方式相对较多


读取文件步骤:



> 
> 1. 包含头文件:#include<fstream>
> 2. 创建流对象:ifstream test;
> 3. 打开文件:test.open("文件路径",打开方式);
> 4. 读数据:四种方式读取
> 5. 关闭文件:test.close();
> 
> 
> 


![img](https://img-blog.csdnimg.cn/img_convert/e025116dceadd12e5950c65f599e6747.png)
![img](https://img-blog.csdnimg.cn/img_convert/6eebcae75cebecec12ab2d1eca3b7f67.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.youkuaiyun.com/topics/618668825)**

}

int main()
{
	test();
	system("pause");
	return 0;
}

2,文件操作

程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放

通过文件可以将数据持久化,需要包含的头文件

文件类型分为两种:

  • 文本文件:文件以文本的ASCLL码形式存储在计算机中
  • 二进制文件:文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂他们

操作文件的三大类

  • ofstream:写操作
  • ifstream:读操作
  • fstream:读写操作

2.1文本文件

2.1.1写文件

步骤:

  1. 包含头文件:#include
  2. 创建流对象:ofstream test;
  3. 打开文件:test.open(“文件路径”,打开方式);
  4. 写数据:test<<“写入的数据”;
  5. 关闭文件:test.close();

//头文件
    ofstream test;
    test.open(“test.txt”, ios::out);
    test << “姓名:小明” << endl;
    test.close();

文件打开方式

打开方式解释
ios::in为读文件而打开文件
ios::out为写文件而打开文件
ios::ate初始位置:文件尾
ios::app追加方式写文件
ios::trunc如果文件存在先删除,再创建
ios::binary二进制方式

文件打开方式可以配合使用,利用” | ”操作符。

2.1.2读文件

读文件与写文件步骤相似,但是读取方式相对较多

读取文件步骤:

  1. 包含头文件:#include
  2. 创建流对象:ifstream test;
  3. 打开文件:test.open(“文件路径”,打开方式);
  4. 读数据:四种方式读取
  5. 关闭文件:test.close();

[外链图片转存中…(img-jyrugdrU-1715813482045)]
[外链图片转存中…(img-9KjTS9NV-1715813482045)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值