面向对象 C++面向对象的三大特性为:封装、继承、多态
C++认为万事万物都皆为对象,对象上有其属性和行为
面向对象之一 ====> 封装 封装是C++面向对象三大特性之一
封装的意义:
将属性和行为作为一个整体,表现生活中的事物
将属性和行为加以权限控制
成员私有化的优点:
可以自己控制读写的权限
对于写,可以检测数据的有效性(在函数接口里安排提示信息) (通常在public里写函数(作为接口),来控制private里的对象是可读的还是读写的,方便修改或读取private里的对象)
构造和析构
构造函数
没有返回值
不用写void
函数名与类名相同
构造函数可以有参数,可以发生重载
创建对象的时候,构造函数会自动调用,而且只调用一次
析构函数
进行清理的操作
没有返回值
不写void
函数名和类名相同
在名称前加~
析构函数不可以有参数的,不可以重载对象
在销毁前会自动调用析构函数,而且只会调用一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <string> using namespace std;class Person {public : Person () { cout << "无参构造函数!" << endl; } Person (int a) { age = a; cout << "有参构造函数!" << endl; } Person (const Person& p){ age = p.age; cout << "拷贝构造函数!" << endl; } ~Person (){} private : int age; }; void t01 () { Person p; } void t02 () { Person p1 (10 ) ; Person p2 = Person (10 ); Person p3 = Person (p2); Person p4 = 10 ; Person p5 = p4; }
什么时候用拷贝构造?
使用一个已经创建完毕的对象来初始化一个新对象
值传递的方式给函数参数传值
以值方式返回局部对象
默认情况下,C++编译器至少给一个类添加3个函数
默认构造函数(无参,函数体为空)
默认析构函数(无参,函数体为空)
默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
如果用户定义有参构造函数,C++不在提供默认无参构造,但是会提供默认拷贝构造
如果用户定义拷贝构造函数,C++不会再提供其他构造函数
析构函数里用delete来清理内存
浅拷贝: 编译器给我们提供的等号赋值操作(带来的问题:同一块内存空间被释放两次,导致程序崩溃) 深拷贝:我们在堆区重新new一块内存(要在析构函数里释放)
1 2 3 4 5 6 7 8 9 10 11 12 Person (const Person& p) { cout << "拷贝构造函数" << endl; m_age = p.m_age; m_height = new int (*p.m_height); } ~Person () { cout << "析构函数" << endl; if (m_height != NULL ) { delete m_height; }
初始化列表:
作用:用来初始化属性 语法:构造函数():属性1(值1),属性2(值2)…()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Person {public : Person (int a, int b, int c) :m_a (a), m_b (b), m_c (c) { } int m_a; int m_b; int m_c; };
类对象作为类的成员:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Phone {public : string brand; Phone (string p_brand) { brand = p_brand; } }; class Person {public : string name; Phone phone; Person (string name, string pbrand) :name (name), phone (pbrand) {}};
static 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <string> using namespace std;class Person {public : static void func () { m_a = 100 ; m_b = 100 ; cout << "static void func 调用" << endl; } static int m_a; int m_b; }; int main () { Person p; p.func (); Person::func; return 0 ; }
空 class 占用的空间为1,因为C++编译器会给每个空对象也分配1字节的空间,是为了区分空对象占内存的位置;每个空对象也应该有一个独一无二的内存地址
静态成员变量类内声明类外初始化
1 2 3 4 5 6 7 8 class Person {public : int m_a; static int m_b; void func () {} static void func2 () {} };
this指针 指向被调用的成员函数所属的对象
形参和成员变量同名时,可以用this指针来区分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Person {public : Person (int age) { age = age; } int age; }; void test01 () { Person p1 (18 ) ; cout << p1. age << endl; } class Person {public : Person (int age) { this ->age = age; } int age; }; void test01 () { Person p1 (18 ) ; cout << p1. age << endl; }
在类的非静态成员函数中返回对象本身,可以return *this;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Person {public : int age; Person (int age) { this ->age = age; } Person& add (Person& p) { this ->age += p.age; return *this ; } }; void test01 () { Person p1 (18 ) ; Person p2 (10 ) ; p1. add (p2); p1. add (p2).add (p2).add (p2); cout << endl; }
空指针访问成员函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Person {public : int age = 0 ; void out01 () { cout << "this is out01" << endl; } void out02 () { cout << "age = " << this ->age << endl; } }; void test01 () { Person *p = NULL ; p->out01 (); p->out02 (); } void out02 () { if (this == NULL ) return ; cout << "age = " << this ->age << endl; }
const 修饰成员函数 常函数:
成员函数后加const后我们称为这个函数为常函数
常函数内不可以修改成员属性
成员属性声明时加关键字mutable后,在常函数中依然可以修改
1 2 3 4 5 6 7 8 9 10 11 12 13 class Person {public : int m_a; mutable int m_b; void showperson () const { this ->m_b = 100 ; } };
常对象:
声明对象前加const称该对象为常对象
常对象只能调用常函数
友元(friend) 目的:让一个函数或者类访问另一个类中的private成员
三种实现方法:
全局函数做友元:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Building {public : Building () { m_sittingRoom = "客厅" ; m_BedRoom = "卧室" ; } string m_sittingRoom; private : string m_BedRoom; }; void Goodgay (Building& building) { cout << "好基友的全局函数 正在访问 " << building.m_sittingRoom << endl; cout << "好基友的全局函数 正在访问 " << building.BedRoom << endl; } class Building { friend void Goodgay (Building& building) ; public : Building () { m_sittingRoom = "客厅" ; m_BedRoom = "卧室" ; } string m_sittingRoom; private : string m_BedRoom; };
类作为友元(一个类能够访问另一个类中的私有成员):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 class Building { friend class goodgay ; public : Building (); public : string m_sittingRoom; private : string m_bedRoom; }; class goodgay {public : Building* building = new Building; void visit () { cout << "正在访问:" << building->m_sittingRoom << endl; cout << "正在访问:" << building->bedRoom << endl; } }; Building::Building () { m_sittingRoom = "客厅" ; m_bedRoom = "卧室" ; } (*有不懂的)成员函数作为友元: #include <iostream> #include <string> using namespace std;class Building ;class GoodGay {public : GoodGay (); void visit () ; void visit2 () ; Building* building; }; class Building { friend void GoodGay::visit2 () ; public : string m_SittingRoom; private : string m_BedRoom; public : Building (); }; Building::Building () { m_SittingRoom = "sitting" ; m_BedRoom = "bed" ; } GoodGay::GoodGay () { building = new Building; } void GoodGay::visit () { cout << "visit函数正在访问" << building->m_SittingRoom << endl; } void GoodGay::visit2 () { cout << "visit2函数正在访问" << building->m_SittingRoom << endl; cout << "visit2函数正在访问" << building->m_BedRoom << endl; } int main () { GoodGay gg; gg.visit (); gg.visit2 (); return 0 ; }
运算符重载 运算符可以和函数一起重载
加号运算符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Person {public : int m_a; int m_b; Person operator +(Person &p) { Person temp; temp.m_a = this ->m_a + p.m_a; temp.m_b = this ->m_b + p.m_b; return temp; } }; void test () { Person p1; p1. m_a = 10 ; p1. m_b = 10 ; Person p2; p2. m_a = 5 ; p2. m_b = 15 ; Person p3 = p1 + p2; cout << p3. m_a << endl << p3. m_b << endl; } class Person {public : int m_a; int m_b; }; Person operator +(Person &p1, Person &p2) { Person temp; temp.m_a = p1. m_a + p2. m_a; temp.m_b = p1. m_b + p2. m_b; return temp; } void test () { Person p1; p1. m_a = 10 ; p1. m_b = 10 ; Person p2; p2. m_a = 5 ; p2. m_b = 15 ; Person p3 = p1 + p2; cout << p3. m_a << endl << p3. m_b << endl; }
总结:对于内置的数据类型的表达式的运算符是不能重载的 总结: 不能滥用运算符
左移运算符重载(只能用全局函数重载)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Person {public : int m_a; int m_b; }; ostream& operator <<(ostream& cout, Person p) { cout << "m_a = " << p.m_a << endl; cout << "m_b = " << p.m_b << endl; return cout; } void test () { Person p; p.m_a = 10 ; p.m_b = 20 ; cout << p << endl; }
重载运算符配合着友元可以输出自定义的数据类型
递增运算符重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class MyInteger { friend ostream& operator <<(ostream& cout, MyInteger p); public : MyInteger () { m_Num = 0 ; } MyInteger& operator ++() { m_Num++; return *this ; } MyInteger operator ++(int ) { MyInteger temp = *this ; m_Num++; return temp; } private : int m_Num; }; ostream & operator <<(ostream& cout, MyInteger p) { cout << p.m_Num << endl; return cout; } void test01 () { MyInteger myint; } void test02 () { MyInteger myint; cout << myint++ ; cout << myint ; } int main () { test01 (); test02 (); return 0 ; }
赋值运算符重载
C++编译器至少给一个类添加4个函数
默认构造函数(无参 , 函数体为空)
默认析构函数(无参 , 函数体为空)
默认拷贝构造函数,对属性进行值拷贝
赋值运算符 operator= 对属性进行拷贝
如果类中有属性指向堆区, 做赋值操作时也会出现深浅拷贝的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Person {public : Person (int age) { m_Age = new int (age); } int * m_Age; Person& operator =(Person& p) { if (m_Age != NULL ) { delete m_Age; m_Age = NULL ; } m_Age = new int (*p.m_Age); return *this ; } }; void test01 () { Person p1 (18 ) ; Person p2 (20 ) ; p2 = p1; }
关系运算符重载
让两个自定义数据类型进行比较
可以根据经验自己写出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Person {public : string name; int age; Person (string name, int age) { this ->name = name; this ->age = age; } int operator >(Person& p) { if (this ->age > p.age) return 1 ; else return 0 ; } };
函数调用运算符重载(简单了解)
函数调用运算 () 也可以重载 叫做仿函数 没有固定写法, 非常灵活
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Person {public : int operator () (int num1, int num2) { return num1 + num2; } }; void test01 () { Person myadd; int ret = myadd (100 , 100 ); cout << "ret = " << ret; } class Add {public : int operator () (int num1, int num2) { return num1 + num2; } }; void test01 () { cout << Add ()(100 , 100 ); }
面向对象之二 ====> 继承
在定义这有些类的时候, 下级别的成员除了有上一级的共性, 还有自己的特性. 这个时候可以考虑使用继承的方式,减少重复代码
基本语法:
普通方法(一定==不要用==, 十分麻烦!!!):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Java {public : void header () { cout << "首页/公开课/登录等....(头部)" << endl; } void footer () { cout << "帮助中心/交流合作等(底部)" << endl; } void list () { cout << "java, python ...(列表)" << endl; } void content () { cout << "其他学科 (目录)" << endl; } };
继承的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class BasePage {public : void header () { cout << "首页/公开课/登录等....(头部)" << endl; } void footer () { cout << "帮助中心/交流合作等(底部)" << endl; } void list () { cout << "java, python ...(列表)" << endl; } }; class Java : public BasePage {public : void content () { cout << "Java学科视频" << endl; } }; class Cpp : public BasePage {public : void content () { cout << "C++学科视频" << endl; } };
继承的好处: 减少重复的代码.
语法: ==class 子类 : 继承方式 父类==
子类 也叫 派生类 父类 也叫 基类
派生类中的成员包含两大部分: 一类是从基类继承过来的(共性) , 一类是自己增加的成员(个性)
继承方式
子类无论以什么方式都访问不到父类中的私有内容.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class Base1 {public : int m_a; private : int m_b; protected : int m_c; }; class Son1 : public Base1 {public : void fun1 () { m_a = 10 ; m_c = 10 ; } }; class Base2 {public : int m_a; private : int m_b; protected : int m_c; }; class Son2 : protected Base2 {public : void fun () { m_a = 10 ; m_c = 10 ; } }; class Base3 {public : int m_a; private : int m_b; protected : int m_c; }; class Son3 : private Base3 {public : void fun () { m_a = 10 ; m_c = 10 ; } };
继承中的对象模型 父类中的所有成员都会传给子类 父类中私有的成员属性被编译器隐藏了, 访问不到, 但是确实被继承下去了
利用 开发人员命令提示工具查看类 的布局
命令: cl /d1 reportSingleClassLayout+类名(前面无空格)+空格+.cpp文件
继承中的构造和析构顺序 父类和子类的构造和析构顺序:
父类先构造后释放,子类后构造先释放. 即:
父类构造 子类构造 子类释放 父类释放
继承中同名成员处理方式 访问子类同名成员 直接反问即可(直接 . ) 访问父类同名成员 需要加作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Base {public : int m_A; Base () { m_A = 10 ; } }; class Son : public Base {public : int m_A; Son () { m_A = 15 ; } }; void test01 () { Son p; cout << "p.m_A = " << (p.m_A) << endl; cout << "p.Base::m_A = " << (p.Base::m_A) << endl; }
如果子类中出现了和父类同名的成员函数,在调用父类传下来的成员函数的时候都应该加上作用域
继承同名静态成员的处理方式 问题:继承中同名的静态成员在子类对象上如何进行访问?
静态成员和非静态成员出现同名,处理方式一致 只不过有两种方法: 通过对象 和 通过类名
访问子类同名成员直接访问即可 ·访问父类同名成员需要加作用域
静态成员属性: 编译阶段分配内存 所有对象共享同一份数据 类内声明类外初始化
多继承语法: 实际开发中并不建议用!
class 子类 : 继承方式 父类1, 继承方式 父类2, ……class Son : public Base, public Base2 {}
父类中出现了同名成员的时候应该加上作用域区分
菱形继承 概念: 两个派生类继承同一个基类,又有一个类继承了两个派生类
问题:
羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时就会产生二义性。
草泥马继承自动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。
当菱形继承的时候, 两个父类有相同的数据, 需要用作用于加以区分 但是我们知道这个数据有一份就可以了,怎么办?
利用虚继承可以解决 可以解决此类问题, 在中间两个子类的继承之前加上 virtual
最上方的类叫做虚基类, 虚继承之后, 数据会变为”只有一个”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class animal {public : int m_Age = 18 ; }; class sheep :virtual public animal{};class camel :virtual public animal {};class sheepcamel : public sheep, public camel {};void test01 () { sheepcamel p; p.sheep::m_Age = 10 ; p.camel::m_Age = 18 ; cout << p.m_Age << endl; }
(继承了指针. 可以通过偏移量来找到那个主题)
面向对象之三 ====> 多态 多态分为两类
静态多态:函数重载和运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态区别:
静态多态的函数地址早绑定, 编译阶段确定函数地址
动态多态的函数地址晚绑定, 运行阶段确定函数地址
动态多态的基本语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Animal {public : virtual void speak () { cout << "动物在说话" << endl; } }; class Cat : public Animal {public : void speak () { cout << "猫在说话" << endl; } }; void doSpeak (Animal& animal) { animal.speak (); } void test01 () { Cat cat; doSpeak (cat); } int main () { test01 (); return 0 ; }
动态多态的满足条件
有继承关系
子类应该重写(不是重载)父类的虚函数, 重写:函数的返回值类型,函数名称,参数列表要完全相同. 子类的函数前面可以不写 virtual
动态多态的使用 父类的指针或者引用来指向子类的对象
多态的优点
代码组织结构清晰
可读性强
利于前期和后期的扩展以及维护
真正的开发中提倡开闭原则:对扩展进行开放, 对修改进行关闭
纯虚函数和抽象类 在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法: virtual 返回值类型 函数名(参数列表)= 0 ;
当类中只要有了一个纯虚函数,这个类也称为抽象类
抽象类特点: 无法实例化对象 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Base {public : virtual void func () = 0 ; }; class Son : public Base {public : void func () { } }; void test01 () { Son p; }
虚析构和纯虚析构 多态使用时,如果子类中有属性开辟到维区,那么父类指针在释放时无法润用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
虚析构和纯虚析构区别:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Animal { public : virtual void speak () = 0 ; virtual ~Animal () = 0 ; }; Animal::~Animal () { cout << "Animal的纯虚析构调用" << endl; } class Cat : public Animal {public : Cat (string name) { m_Name = new string (name); } virtual void speak () { cout << *m_Name << "猫在说话" << endl; } string* m_Name; ~Cat () { if (m_Name != NULL ) delete m_Name; } }; void test01 () { Animal* animal = new Cat ("Tom" ); animal->speak (); delete animal; }
内存结构 内存四区:
代码区:存放函数体的二进制代码,由操作系统进行管理的
全局区:存放全局变最和静态变量以及常量
栈区:由编译器自动分配释放存放函数的参数值局部变量等
堆区:由程序员分配和释放若程序员不释放程序结束时由操作系统回收
内存四区的意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
程序运行之前: 代码区 :存放CPU执行的机器指令(二进制的)
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令全局区 :全局变量,常量和静态变量存放在此
常量区包括字符串常量(双引号引起来的)和其他常量(const 修饰的局部变量不在全局区,全局变量在全局区)
该区域的数据在程序结束后由操作系统释放
总结:
C++中在程序运行前分为全局区和代码区
代码区特点是共享 和只读
全局区中存放全局变量、静态变量、常量
常量区中存放const修饰的全局常量和字符串常量
程序运行之后 栈区 :由编译器自动分配释放,存放函的参数值(形参),局部变量等
注意事项:
不要返回局部变量的地址
栈区开辟的数据由编译器自动释放
1 2 3 4 5 6 7 8 9 10 11 12 13 int * func () { int a = 10 ; return &a; } int main () { int *p = func (); cout << *p << endl; cout << *p << endl; return 0 ; }
程序运行的结果为: 10 和 乱码(因为这一块内存已经被释放了)
堆区 :
程序员分配释放,若程序员不释放程序结束时,由操作系统回收
在C++中主要利用 new 在堆区开辟内存
在堆区开辟内存:int *p = new int (10); return p;
默认参数 :
函数的默认参数,自己传进去了就用自己的,没有的话就用默认的,但是,如果函数声明有了默认参数,函数的实现的时候就不能有默认参数。(声明‘上面的函数头’和实现‘下面实现函数的时候的函数头’只能有一个有默认参数)
占位参数 :
(只写一个数据类型) 函数头: void func(int a, int); 函数调用:func(10, 20);
函数重载 :
函数的名称相同 同一个作用域下 参数的类型,个数,顺序不同 函数的返回值不可以作为函数重载的条件
文件操作 程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
C++中对文件操作需要包含头文件<fstream>
文件类型分为两种:
文本文件-文件以文本的ASCll码形式存储在计算机中
二进制文件-文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
操作文件的三大类:
ofstream:写操作
ifstream:读操作
fstream:读写操作
写文本文件 写文件步骤如下:
1.包含头文件#include <fstream>
2.创建流对象ofstream ofs;
3.打开文件ofs.open("文件路径”, 打开方式);
4.写数据ofs<<“写入的数据";
5.关闭文件ofs.close();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <fstream> using namespace std;void test01 () { ofstream ofs; ofs.open ("test.txt" , ios::out); ofs << "这是一个测试文件" << endl; ofs << "用来测试一下这个文件是否有写入成功" << endl; ofs << "如果写成功了, 你就会看见这几行字" << endl; ofs << "好运~ " << endl; ofs.close (); } int main () { test01 (); cout << "写入成功!" << endl; return 0 ; }
读文本文件 读文件步骤如下:
包含头文件#include<fstream>
创建流对象ifstream ifs;
打开文件并判断文件是否打开成功ifs.open(“文件路径”, 打开方式);
读数据 四种方式读取
关闭文件ifs.close();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <fstream> #include <string> using namespace std;void test01 () { 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) { cout << c << endl; } ifs.close (); } int main () { test01 (); cout << "文件打开成功!" << endl; return 0 ; }
在对文件进行写入的时候, 对于字符串文件最好用 char 字符串的方式来定义, 因为用C++内置的 string 类型有时候会出现一些错误
写二进制文件 用二进制文件来写数据可以写入一些自定义数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 class Person {public : char m_Name[60 ]; int m_Age; }; void test01 () { Person p = {"zhangsan" , 18 }; ofstream ofs; ofs.open ("person.txt" , ios::out | ios::binary); ofs.write ((const char *)&p, sizeof (Person)); ofs.close (); }
读二进制文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Person {public : char m_Name[60 ]; int m_Age; }; void test01 () { ifstream ifs; 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.m_Name << endl << "年龄 = " << p.m_Age << endl; ifs.close (); }