const
#include <iostream>
using namespace std;
const修饰指针--常量指针,const int *p;p=&a;*p=1/错误,指针指向固定的值;
const修饰常量--指针常量,int * const p;p=&a/错误;*p=1,指针指向固定的地址;
const既修饰指针也修饰常量,const * int *p;
内存分区模型:
- 代码区:放二进制代码
- 全局区:存放全局变量和静态变量(static)以及常量等;
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等;
- 堆区:由程序员分配和释放,若程序员不释放,操作系统回收。
利用new在堆区开辟数据
int * p=new int(10)创建一个数据10,new返回该数据类型的指针
int * arr=new int[10]创建10个数据
引用
int a=10;int c=10;
int &b=a;//给变量起别名,a,b的数据类型一致,a,b操作同一块内存
注意:1.引用必须要初始化{int &b;错误}{int &b=a;正确};2.引用一旦初始化,不能改为其他变量的别名,{b=c;错误}
引用做函数参数
//交换函数
void Swap01(int a,int b){//值传递,不改变主函数实参
int temp=b;
b=a;
a=temp;
}
void Swap02(int* a,int* b){//地址传递,改变主函数实参
int temp=*b;
*b=*a;
*a=temp;
}
void Swap03(int &a,int &b){//引用传递,改变主函数实参
int temp=b;
b=a;
a=temp;
}
Swap01(a,b);
Swap02(&a,&b);
Swap03(a,b);
引用作为返回值类型
int& test01(){
int a=10;
return a;}//a在栈区
int& b=test01();//正常输出10,编译器保留一次
int& b=test01();//数据被回收了,出错
int& test02(){
static int a=10;//a放在全局区,程序结束后系统释放
return a;}//
int& c=test02();//输出c的值是10
test02()=1000;//如果函数的返回值是引用,这个函数可以作为左值,输出c的值是1000
引用的本质是指针常量int * const p=&a;
常量引用
修饰形参,防止误操作
int a=10;
int &p=a;正确
int &p=10;错误
Const int &p=10;正确//编译器自动优化,int temp=10;const int& p=temp;
const int &p=a;p=10;错误,加入const变为只读,不可修改
Void show(const int &a){
a=100;//错误,常量引用不能被修改
}
函数的默认参数
int fun(int a=10,int b=20);//声明有默认参数时
int fun(int a,int b){//实现不要默认参数
return a+b;
}
声明和实现只能有一个有默认参数
函数占位参数
void fun(int a,int){//只写数据类型
cout<<a<<endl;
}
fun(10,10);//必须传2个值进去
void fun(int a,int=10){//占位参数可以默认
cout<<a<<endl;
}
fun(10);//可以只传1个值进去
函数重载
函数名称相同,参数类型不同或个数不同或顺序不同,提高复用性.必须在同一个作用域下
void func()
void func(int a)
void func(int a, double b)
int func(int a, double b) //错误,无法发生重载
void func(int &a);
void func(const int &a);
func(10)//进入void func(const int &a);而不是void func(int &a);const int &a=10合法,int &a=10;不合法
void func(int a,int b=10);
void func(int a);
func(10);//函数重载碰到默认参数,以上两个函数都可以进入,错误,因此不要加默认值
类
class student{
public:
string s_name;
int number;
void showStudent(){
Cout<<”姓名:”<<name<<”学号:”<<number<<endl;
}
void setName(string name){
s_name=name;
}
void setId(int id){
number=id;}
}
访问权限
- public公共权限 类内外都可以访问
- protected保护权限 类内可以访问类外不可以访问 子类可以访问父类的保护内容
- private私有权限 类内可以访问类外不可以访问 子类不可以访问父类的保护内容
class person{
public:
string name;
protected:
string car;
private:
int password;
}
int main(){
person P1;
P1.name=”张三”;
P1.car=”奔驰”;//错误,类外访问不到
P1.password=123456;//错误,类外访问不到
}
class和struct区别
class C1{
int m_A;//默认权限:私有
}
struct C2{
int m_A;//默认权限:公共
}
int main(){
C1 c1;
c1.m_A=100;//报错,类外不可以访问
C2 c2;
c2.m_A=100;//成功
}
成员属性设置为私有
class Person
{
private:
string m_name;//要求可读可写
int age;//要求只读
public:
void setName(string name){//写
m_name=name;
}
void getName(){//读
return m_name;
}
void getAge(){//读
return m_age;
}
}
构造函数和析构函数
构造函数用于初始化对象,析构函数用于清理对象
class Person
{
Person()
{
cout<<"构造函数"<<endl;
}
~Person()
{
cout<<"析构函数"<<endl;
}
}
void test(){
Person p;
}
int main(){
test();//几乎同时调用构造函数和析构函数
Person p;//调用构造函数,函数main结束时调用析构函数
}
构造函数的分类和调用
两种构造方式:
- 按参数分类:有参构造,无参构造
- 按类型分类:普通构造和拷贝构造
三种调用方式:
- 括号法
- 显示法
- 隐式转换法
class Person{
public:
int age;
Person(int a){
age=a;
cout<<"有参构造函数"<<endl;
}
Person(const Person &p){//拷贝构造
age=p.age;
}
}
void test(){
//括号法
Person p1;//默认构造函数调用,不加()
Person p2(10);//有参构造函数调用
Person p3(p2);//拷贝构造函数调用
//显示法
Person p1;
Person p2=Person(10);//有参构造
Person p3=Person(p2);//拷贝构造
Person(10);//匿名对象,系统运行到这会立即收回匿名对象
//隐式转换法
Person p4=10;//相当于Person p4=Person(10);有参构造
Person p5=p4;//相当于Person p5=Person(p4);拷贝构造
}
拷贝构造函数调用时机
1.使用一个已经创建完毕的对象来初始化一个新对象
void test(){
Person p1;
Person p2(p1);
}
2.值传递的方式给函数参数传值
void doWork(Person p){}
void test(){
Person p;
doWork(p);
}
3.值方式返回局部对象
Person doWork2(){
Person p;
return p;//输出p
}
void test(){
Person p=doWork2();//接收到的p地址与上面输出p的地址不同,深拷贝
}
构造函数调用原则
默认情况下,C++编译器至少给一个类添加3个函数
1.默认构造函数(默认函数体为空)
2.默认析构函数(默认函数体为空)
3.默认拷贝构造函数,对所有属性进行值拷贝
class Person{
public:
int age;
Person(){
cout<<"默认构造函数"<<endl;
}
~Person(){
cout<<"默认析构函数"<<endl;
}
Person(int a){//提供有参构造函数,编译器不再提供默认无参构造,依然提供拷贝构造
age=a;
cout<<"有参构造函数"<<endl;
}
Person(const Person &p){//拷贝构造//提供拷贝构造函数,编译器不再提供其他构造函数
age=p.age;
cout<<"拷贝构造函数"<<endl;
}
}
深拷贝与浅拷贝
- 浅拷贝:简单赋值操作
- 深拷贝:在堆区重新申请空间进行拷贝操作
class Person{
public:
int age;
int *m_Height;
Person(){
cout<<"默认构造函数"<<endl;
}
~Person(){
if(m_Height!=NULL){
delete m_Height;
m_Height=NULL;
}
cout<<"默认析构函数"<<endl;
}
Person(int a,int Height){//提供有参构造函数,编译器不再提供默认无参构造,依然提供拷贝构造
age=a;
m_Height=new int(Height);
cout<<"有参构造函数"<<endl;
}
Person(const Person &p){//拷贝构造//提供拷贝构造函数,编译器不再提供其他构造函数
age=p.age;
//m_Height=p.m_Height;编译器默认,浅拷贝,报错
m_Height=new int(*p.m_Height);//深拷贝,自动返回地址
cout<<"拷贝构造函数"<<endl;
}
}
初始化列表
class Person{
public:
int m_A;
int m_B;
int m_C;
Person(int a,int b,int c){
m_A=a;
m_B=b;
m_C=c;
cout<<"传统初始化操作"<<endl;
}
Person(int a,int b,int c):m_A(a),m_B(b),m_C(c){
cout<<"初始化列表初始化属性"<<endl;
}
}
类对象作为类成员
class A();
class B{
A a;
}
静态成员
静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
class Person{
public:
static int m_A;//类内声明
private:
static int m_B;//类外无法访问
}
static int Person::m_A=10;//类外初始化
void test(){
Person p1;
p1.m_A=100;//通过对象访问
Person::m_A=200;//通过类名访问
}
静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
class Person{
public:
static int m_A;//类内声明
int m_B;
static void func()
{
m_A=100;//静态成员函数可以访问
m_B=100;//非静态成员函数不可以访问,报错
}
private:
static void func2()
{
}
}
static int Person::m_A=10;//类外初始化
Person p;
p.func();//通过对象访问
p.func2();//类外访问不到私有函数
Person::func();//通过类名访问
C++对象模型
成员函数和成员变量分开存储
class Person{}
void test(){
Person p;
cout<<"size of class: "<<sizeof(p)<<endl;//大小为1,编译器给每个空对象分配一个字节空间,用于区别空对象占内存的位置
}
class Person2{
int m_A;
static int m_B;
void func(){}
static void func2(){}//静态不属于类对象,非静态属于类对象,分开存储
}
指针
this指针
同一份代码会被多个同类型的对象调用,利用this指针区分不同对象,this指针指向被调用的成员函数所属的对象。
class Person
{
public:
int age;
Person(int age){
this->age=age;}
Person& addP(Person &p){//用引用的方式,不加&是值的方式,返回一个新的对象,引用返回的还是原p
this->age+=age;//this指针指向被调用成员的对象
return *this;//*this就是一个Person对象
}
}
void test(){
Person p1(10);
Person p2(20);
p2.addP(p1).addP(p1).addP(p1).addP(p1);//链式编程
cout<<"p2的年龄是:"<<p2.age<<endl;
}
空指针访问成员函数
class Person
{
public:
int age;
void showname(){
cout<<"class name is Person"<<endl;;}
void showage(){
if(this==NULL){
return;
}
cout<<this->age<<endl;}
}
void test(){
Person*p=NULL;//空指针,age没有值,无法访问age
p->showname();//正确
p->showage();//错误
}
const 修饰成员函数
常函数:
常函数内不可以修改成员属性;
想要修改,在属性声明时加关键字mutable;
常对象:
常对象只能调用常函数;
class Person
{
public:
//this指针的本质是指针常量,指针的指向不可修改,但是指向的值可以改
//Person * const this
void showPerson() const//this 既是指针常量也是常量指针
{
this->A=100;//错误,
this->B=100;//正确
}
void showPerson()
{
this->A=100;//正确,
}
void func(){}
int A;
mutable int B;
}
void test(){
const Person p;//常对象
p.A=100;//错误,不可修改普通属性
p.B=100;//正确
p.func();//错误,常对象不可调用普通函数
p.showPerson();//正确
}
友元
友元的三种实现:
- 全局函数做友元
class Building{
friend void goodFriend(Building* building);//全局函数做友元,goodFriend是Building的好朋友,可以访问它的私有成员
public:
Building(){
sittingroom="客厅";
bedroom="卧室";
}
string sittingroom;
private:
string bedroom;
}
void goodFriend(Building* building){
cout<<"好朋友全局函数正在访问:"<<
building->sittingroom<<endl;
cout<<"好朋友全局函数正在访问:"<<
building->bedroom<<endl;//正确
}
int main(){
Building building;
goodFriend(&building);
}
- 类做友元
class Building{
friend class goodFriend;//goodFriend是Building的好朋友,可以访问它的私有成员
public:
Building(){}
string sittingroom;
private:
string bedroom;
}
//类外也能实现成员函数
Building::Building(){
sittingroom="客厅";
bedroom="卧室";
}
class goodFriend(){
public:
void visit();
Building * building;
}
goodFriend::goodFriend(){
building=new Building;//创建对象
}
goodFriend::visit(){
cout<<"好朋友正在访问:"<<building->sittingroom<<endl;
cout<<"好朋友正在访问:"<<building->bedroom<<endl;
}
int main(){
goodFriend gf;
gf.visit();
}
- 成员函数做友元
class Building{
friend void goodFriend::visit();//成员函数做友元,goodFriend是Building的好朋友,可以访问它的私有成员
public:
Building(){
sittingroom="客厅";
bedroom="卧室";
}
string sittingroom;
private:
string bedroom;
}
class goodFriend(){
public:
goodFriend(){
building=new Building;
}
void visit(){
cout<<"visit函数正在访问"<<building.sittingroom<<endl;
cout<<"visit函数正在访问"<<building.bedroom<<endl;
}//让visit可以访问building中的私有成员
void visit2(){
cout<<"visit2函数正在访问"<<building.sittingroom<<endl;}//让visit2不可以访问building中的私有成员
Building * building;
}
int main(){
goodFriend gf;
gf.visit();
gf.visit2();
}
运算符重载
加法运算符重载
class Person
{
public:
Person& operator+(Person&p){//成员函数重载
Person temp;
temp.A=this->A+p.A;
temp.B=this->B+p.B;
return temp
}
int A;
int B;
}
//全局函数重载,功能同成员函数重载一样
Person& operator+(Person&p1,Person&p2){
Person temp;
temp.A=p1->A+p2.A;
temp.B=p1->B+p2.B;
return temp
}
Person& operator+(Person&p1,int num){//Person+int
Person temp;
temp.A=p1->A+num;
temp.B=p1->B+num;
return temp
}
void test(){
Person p1;
p1.A=10;
p1.B=10;
Person p2;
p2.A=10;
p2.B=10;
Person p3=p1+p2;//等价于p3=p1.operator+(p2);
Person p4=p1+100;
}
左移运算符重载
class Person
{
friend ostream& operator<<(ostream& cout,Person &p);
private://私有
int A;
int B;
}
public:
Person(int a, int b){
A=a;
B=b;
}
//只能利用全局函数重载
ostream& operator<<(ostream& cout,Person &p){
cout<<"p.A="<<p.A<<", p.B="<<p.B<<endl;
return cout;//cout只是别名,可以修改
}
void test(){
Person p(10,10);
cout<<p<<endl;
}
递增运算符重载
class MyInteger{
friend ostream& operator<<(ostream& cout,MyInteger& myint);
public:
MyInteger(){
num=0;
}
//前置递增
MyInteger& operator++(){
num++;
return *this;
}
//后置递增
MyInteger& operator++(int){//int 代表占位参数,可以用于区分前置递增和后置递增
MyInteger temp=*this;
num++;
return temp;
}
private:
int num;
}
ostream& operator<<(ostream& cout,MyInteger& myint){
cout<<myint<<endl;
return cout;
}
void test(){
MyInteger myint;
cout<<myint++<<endl;
cout<<++myint<<endl;
}
赋值运算符重载
C++编译器至少给一个类添加4个函数
1.默认构造函数,函数体为空
2.默认析构函数,函数体为空
3.默认拷贝函数,对属性进行值拷贝
4.赋值运算符operater=,对属性进行值拷贝
class Person
{
public:
int * Age;
Person(int age){
Age=new int(age);
}
~Person(){
if(Age!=NULL){
delete Age;
Age=NULL;
}
Person& operator=(Person&p){//深拷贝
//先判断是否有属性在堆区,如果有先释放干净
if(Age!=NULL){
delete Age;
Age=NULL;
}
this->Age=new int(*p.Age);
return *this;
}
}
}
void test01(){
Person p1(18);
Person p2(28);
Person p3(38);
p2=p1;//浅拷贝,p1,p2的Age都指向同一块内存,两者都释放一次,第二次释放时会报错,堆区内存重复释放
cout<<"p2的年龄是:"<<*p2.Age<<endl;
p3=p2=p1;
}
关系运算符重载
class Person
{
public:
string Name;
int Age;
Person(int age,string name){
Age=age;
Name=name;}
bool operator==(Person&p){
if(p.Name==this->Name && p.Age==this->Age){
return true;
}
return false;
}
bool operator!=(Person&p){
if(p.Name==this->Name && p.Age==this->Age){
return false;
}
return true;
}
}
void test(){
Person p1=(18,"Tom");
Person p2=(18,"Tom");
Person p3=(28,"Tom");
if(p1==p2){
cout<<"p1和p2相同"<<endl;
}
if(p1!=p3){
cout<<"p1和p2不同"<<endl;
}
}
函数调用运算符()重载
class MyPrint{
public:
void operator()(string test){
cout<<test<<endl;
}
}
class MyAdd{
public:
int operator()(int num1,int num2){
return num1+num2;
}
}
void test(){
MyPrint myprint;
myprint("Hello World");//由于重载后使用的方式非常像函数的调用,因此称为仿函数。
MyAdd myadd;
cout<<myadd(2,3)<<endl;
cout<<MyAdd()(2,3)<<endl;//匿名函数对象
}
继承
class BasePage{
public:
void header(){
cout<<"首页、公开课、登录..."<<endl;}
}
class Java:public BasePage{//class 子类:继承方式 父类,子类也叫派生类,父类也叫基类
void conter(){
cout<<"Java学科视频"<<endl;}
}
class Python:public BasePage{
void conter(){
cout<<"python学科视频"<<endl;}
}
继承方式
公共继承,保护继承,私有继承
A类是父类,私有的属性c在子类中无法访问,保护继承下父类共有属性和保护属性在子类中都是保护属性,私有继承下父类共有属性和保护属性在子类中都是私有属性。
利用开发人员命令提示工具查看对象模型.。
继承中的构造和析构顺序
父类构造---->子类构造---->子类析构---->父类析构
继承同名成员处理方式
- 子类对象可以直接访问子类中的同名成员
- 子类对象加作用域可以访问到父类同名成员
- 当子类和父类拥有同名成员函数,子类会隐藏父类中的同名成员函数,加作用域可以访问父类中同名函数。
class Base{
public:
int A;
Base(){A=100;}
void func(){cout<<"base-func"<<endl;}
void func(int a){cout<<"base-func a"<<endl;}
}
class Son:public Base{
int A;
Base(){A=200;}
void func(){cout<<"son-func"<<endl;}
}
void test(){
Son s;
cout<<s.A<<endl;//输出200
cout<<s.Base::A<<endl;//输出100
s.func()//输出son-func
s.Base::func()//输出base-func
s.func(10);//报错,无法访问,父类同名函数被子类的同名函数隐藏,无论有无参
s.Base::func(10);//输出base-func a
}
同名静态成员处理方式
同非静态处理方式一样
- 访问子类同名成员,直接访问即可
- 访问父类同名成员,需要加作用域
class Base{
public:
static int A;
Base(){A=100;}
static void func(){cout<<"base-func"<<endl;}
static void func(int a){cout<<"base-func a"<<endl;}
}
int Base::A=100;
class Son:public Base{
static int A;
Base(){A=200;}
static void func(){cout<<"son-func"<<endl;}
}
int Son::A=100;
void test(){
Son s;
//通过对象访问
cout<<s.A<<endl;
cout<<s.Base::A<<endl;
s.func()//输出son-func
s.Base::func()//输出base-func
s.Base::func(10);//输出base-func a
//通过类名访问
cout<<"son下A="<<Son::A<<endl;
cout<<"base下A="<<Son::Base::A<<endl;
Son::func()//输出son-func
Son::Base::func()//输出base-func
Son::Base::func(10);//输出base-func a
}
多继承语法
C++允许一个类继承多个类,但不推荐
多继承可能会引发父类中由同名成员出现,需要加作用域
class Base1{
public:
int A;
Base1(){A=10;}
}
class Base2{
public:
int A;
Base1(){A=20;}
}
class Son:public Base1,public Base2{
}
void test(){
Son s;
cout<<"Base1:"<<s.Base1::A<<endl;
cout<<"Base2:"<<s.Base2::A<<endl;
}
菱形继承
概念:两个派生类继承同一个基类,又有某个类继承同时继承这两个派生类。
问题:容易引发二义性,子类继承两份相同的数据,使用虚继承解决。
class Animal{
public:
int Age;};
class Sheep:virtual public Animal{};//加上关键字virtual,虚继承
class Camel:virtual public Animal{};//Animal是虚基类
class Sheepcamel:public Sheep,public Camel{};
void test(){
Sheepcamel sc;
sc.Sheep::Age=18;
sc.Camel::Age=28;//覆盖了
cout<<"羊的年龄:"<<sc.Sheep::Age<<endl;
cout<<"驼的年龄:"<<sc.Camel::Age<<endl;//需要加作用域区分
//这份数据只需要有一份就可以,菱形继承数据有两份,造成资源浪费,使用virtual进行虚继承,都输出28
cout<<"驼的年龄:"<<sc.Age<<endl;//输出28
}
//vbptr虚v基类b指针ptr,指向vbtable虚基类表
多态
好处:
- 对修改封闭,对扩展开放,维护性高
- 组织结构清晰
- 可读性强
两种多态:
- 静态多态:包含函数重载和运算符重载等,函数地址早绑定,编译阶段确定函数地址
- 动态多态:派生类和虚函数实现运行时多态,函数地址晚绑定,运行阶段确定函数地址(这里讲动态多态)
class Animal{
public:
void Speak1(){cout<<"动物在说话"<<endl;}
virtual void Speak2(){cout<<"动物在说话"<<endl;}//加virtual虚函数,实现地址晚绑定
};
class Cat:public Animal{
public:
void Speak1(){cout<<"小猫在说话"<<endl;}
void Speak2(){cout<<"小猫在说话"<<endl;}
};
void doSpeak1(Animal& animal){
animal.speak1();
}
void doSpeak2(Animal& animal){//父类引用
animal.speak2();
}
void test(){
Cat cat;
doSpeak1(cat);//输出动物在说话,地址早绑定,在编译阶段确定函数地址
doSpeak2(cat);//输出小猫在说话,地址晚绑定,在运行阶段确定函数地址
}
动态多态满足条件:
- 有继承关系
- 子类重写父类虚函数
动态多态使用:
- 父类的指针或者引用,执行子类对象
多态的底层原理
纯虚函数和抽象类
父类中的虚函数的实现是毫无意义的,主要是调用子类重写的内容,因此可以将虚函数改为纯虚函数。
当类中有纯虚函数,这个类也称为抽象类。
抽象类的特点:无法实例化对象;子类必须重写抽象类中的纯虚函数,否则也属于抽象类。
class Base{
public:
virtual void func()=0;//纯虚函数,无法实例化对象
}
class Son:public Base{
public:
void func(){cout<<"子类"<<endl;}
}
void test(){
Base b;//报错
Son s;//可以实例化
Base* b=new Son;//开辟在堆区
b->func();
delete b;//手动删除
}
虚析构和纯虚析构
问题:如果子类中有属性开辟到堆区,父类指针在释放时无法调用到子类的析构代码。
解决办法:将父类中的析构函数改为虚析构或者纯虚析构(也是抽象类)
class Animal{
public:
virtual void Speak()=0;
Animal(){cout<<"animal构造"<<endl;}
virtual ~Animal(){cout<<"animal析构"<<endl;}//利用虚析构解决父类指针释放不干净的问题。
//或者纯虚析构,既需要声明也需要实现,抽象类
virtual ~Animal()=0;
};
Animal::~Animal(){cout<<"animal纯虚析构"<<endl;}
class Cat:public Animal{
public:
string *Name;
Cat(string name){
cout<<"cat 构造"<<endl;
Name=new string(name);//堆区
}
~Cat(){
if(Name!=NULL){
cout<<"cat 析构"<<endl;
delete Name;
Name=NULL;}
}
void Speak(){cout<<*Name<<"小猫在说话"<<endl;}
};
void test(){
Animal* animal=new Cat("Tom");
animal->Speak();
delete animal;//父类指针在析构时不会调用子类中的析构函数,导致子类如果有堆区数据会导致内存泄漏,添加virtual到 ~Animal()
}
文件操作
需要添加头文件#include
文件类型分类:
- 文本文件,以ASCII码的形式存储在计算机中
- 二进制文件,以文本二进制的形式存储在计算机中
操作:
- 写:ofstream(o代表output)
- 读:ifstream,(i代表input)
- 读写:fstream
写文本文件
ofstream ofs;
ofs.open(“文件路径”,文件打开方式);
ofs<<“写入数据”<<endl;
ofs.close();
文件打开方式:
void test(){
ofstream ofs;
ofs.open("test.txt",ios::out);//打开文件
ofs<<"姓名:张三"<<endl;//写入数据
}
读文本文件
ifstream ifs;
ifs.open(“文件路径”,文件打开方式);
四种方式读取文件
ifs.close();
void test(){
ifstream ifs;
ifs.open("test.txt",ios::in);//打开文件
if(!ifs.is_open()){
cout<<"文件打开失败"<<endl;
return;}
//读数据,四种
//第一种,一行一行的读
char buf[1024]={0};//字符数组
while(ifs>>buf){
cout<<buf<<endl;}
//第二种
char buf[1024]={0};
while(ifs.getline(buf,sizeof(buf))){
cout<<buf<<endl;
}
//第三种
string buf;
while(getline(ifs,buf)){
cout<<buf<<endl;
}
//第四种,一个字节一个字节地读,效率低,不推荐
char c;
while((c=ifs.get())!=EOF){//end of file文件尾
cout<<c;
}
ifs.close();
}
写二进制文件
以二进制方式对文件进行读写,打开方式指定ios::binary
函数原型:ostream& write(const char* buffer,int len)
字符指针buffer指向内存中一段存储空间,len是读写的字节数
#include <iostream>
class Person{
public:
char Name[64];
int Age;
}
void test(){
ofstream ofs;
ofs.open("person.txt",ios::out | ios::binary);
//或两行合到一起ofstream ofs.open("person.txt",ios::out | ios::binary);
Person p={"张三",18};
ofs.write((const char *)&p,sizeof(Person));}
ofs.close();
读二进制文件
函数原型:ostream& read(const char* buffer,int len)
字符指针buffer指向内存中一段存储空间,len是读写的字节数
#include <iostream>
class Person{
public:
char Name[64];
int Age;
}
void test(){
ifstream ifs.open("person.txt",ios::in | ios::binary);
if(!ifs.is_open()){
cout<<"文件打开失败!"<<endl;
return;
}
Person p;
ifs.read((char*)&p,sizeof(Person));
cout<<"姓名:"<<p.Name<<" 年龄:"<<p.Age<<endl;
ifs.close();