1.内存分区模型:
C++程序在执行时,将内存大方向划分为四个区域
(1)代码区:存放函数体的二进制代码,由操作系统进行管理
(2)全局区:存放全局变量和静态变量以及变量
(3)栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
(4)堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
四区的意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
在程序运行前:
生成了exe可执行程序,未执行该程序前分为两个区域
代码区:
存放CPU执行的机器指令
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区:
全局变量和静态变量存放在此
全局区还包含了常量区,字符串常量和其他常量也存放在此
该区域的数据在程序结束后由操作系统释放
栈区:
由编译器自动分配释放,存放函数的参数值,局部变量等
注意事项:不要返回局部变量的地址
形参数据也会放在栈区
堆区:
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中主要利用new在堆区开辟数据
cpp
#include<iostream>
using namespace std;
int* func()
{
//利用new关键字,将数据开辟到堆区
int* p = new int(10);
return p;
}
//这里函数中的p被释放之前,把地址传给了main中的P,以访问堆区的10
int main()
{
//在堆区开辟数据
int* p = func();
//10 10 地址
cout << *p << endl;
cout << *p << endl;
cout << &p << endl;
system("pause");
return 0;
}
new操作符:
cpp
#include<iostream>
using namespace std;
int* func()
{
//在堆区创建整型数据
//new返回的是 该数据类型的指针
int* p = new int(10);
return p;
}
void test01()
{
int* p = func();
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
//堆区的数据由程序员管理
//利用关键字delete释放
delete p;
//cout << *p << endl;该操作会报错,内存已经被释放
}
//利用new开辟堆区的数组
void test02()
{
//创建10个整型的数组,返回数组的首元素地址
int *arr =new int[10];
//arr就变成了数组名
arr[1] = 1;
//释放数组需要加一个中括号
delete[]arr;
}
int main()
{
test01();
system("pause");
return 0;
}
2.引用
基本用法:
cpp
#include<iostream>
using namespace std;
//引用:给变量起别名
//语法:数据类型 &别名 = 原名;(数据类型得一样)
int main()
{
int a = 10;
int& b = a;
cout << a << endl;
cout << b << endl;
b = 20;
cout << a << endl;
cout << b << endl;
system("pause");
return 0;
}
注意事项:
(1)引用必须初始化
(2)引用一旦初始化后,就不可以更改
引用作函数传递参数:
cpp
#include<iostream>
using namespace std;
void func(int& a, int& b)
{
int num = a;
a = b;
b = num;
}
int main()
{
int a = 0;
int b = 10;
func(a, b);//引用传递,形参会修饰实参
cout << a << endl;
cout << b << endl;
system("pause");
return 0;
}
引用做函数返回值:
cpp
#include<iostream>
using namespace std;
//引用作函数返回值
//1.不要返回局部变量的引用
int& test01()
{
static int a = 10;//静态变量放在全局区
return a;
}
int main()
{
int &num = test01();
cout << num << endl;
cout << num << endl;
test01() = 1000;//如果函数的返回值是引用,这个函数调用可以作为左值
cout << num << endl;
cout << num << endl;
system("pause");
return 0;
}
引用的本质:
引用的本质是一个指针常量
常量引用:
cpp
#include<iostream>
using namespace std;
//加上const之后,值不可改,避免出现错误
void showNum(const int& a)
{
cout << a << endl;
}
int main()
{
//常量引用
//使用场景:用来修饰形参,防止误操作
//加上const之后,编译器将代码修改 int temp = 10;const int & ref =temp;
//const int& ref = 10;
int a = 1000;
showNum(a);
system("pause");
return 0;
}
函数默认参数:
cpp
#include<iostream>
using namespace std;
//函数默认参数
//int func(int a, int b, int c)可以这样写
//也可以下面这样写
//注意事项:
//如果在函数定义实现处写出默认值,就可以在main中省略后两个值的输入
//声明和实现处只能有一处默认值
//在函数内部不能再赋予其其他默认值
//语法: 返回值类型 函数名 (形参=默认值){}
int func(int a, int b=20, int c=30)
{
return a + b + c;
}
int main()
{
cout << func(10, 20, 30) << endl;
system("pause");
return 0;
}
函数占位参数:
cpp
//函数占位参数
//返回值类型 函数名(数据类型,占位){}
//下面这个函数,使用int占在那里int还可以有默认值
void func(int a, int=10)
{
cout << "this is func" << endl;
}
int main()
{
func(10, 10);
system("pause");
return 0;
}
函数重载:
cpp
//函数重载
//作用:函数名可以相同,提高复用性
//函数重载满足条件:1 同一个作用域下 2 函数名称相同 3 函数参数类型不同 或者 个数不同 或者顺序不同
//函数的返回值不可以当作函数重载的条件
void func(long int b,int a)
{
cout << "func的调用" << endl;
}
void func(int a)
{
cout << "func" << endl;
}
void func(long int a)
{
cout << "func" << endl;
}
void func(int a,long int b)
{
cout << "func" << endl;
}
int main()
{
func(10);
system("pause");
return 0;
}
函数重载注意事项:
cpp
//1.引用作为函数重载的条件
//下面这两个这样写是被允许的 const也算不同类型的一种
void func(int& a)
{
}
void func(const int& a)
{
}
int main()
{
//这样会调用上面的函数
int a = 10;
func(a);
//这样会调用下面的参数
//直接传入10,上面的函数不合法,传入下面的函数含有const,编译器会开辟出int t =10 int &a=t来使其合法
func(10);
system("pause");
return 0;
}
cpp
//2.函数重载遇到默认参数
void func(int a,int b=10)
{
}
void func(int a)
{
}
int main()
{
func(10);//这样会出现歧义,无法重载
return 0;
}
类和对象
c++面向对象的三个特性:封装 继承 多态 万事万物都可以作为对象,对象上有其属性和行为
设计一个圆类,来计算其周长
cpp
//创建全局变量
double pi = 3.14;
//class代表设计一个类,后面紧跟类的名称
class Circle
{
//一个类需要具备的要素;访问权限,属性,行为
//访问权限
public:
//属性
int m_r;
//行为
//获取圆的周长
double calculator()
{
return 2 * pi * m_r;
}
};
int main()
{
//通过该类,创建具体的对象(实例化)
Circle c1;
//给圆对象进行属性的赋值
c1.m_r = 10;
//使用行为(函数)进行相应操作
cout << "圆的周长为: " << c1.calculator() << endl;
system("pause");
return 0;
}
cpp
#include<string>;
class Student
{
public:
//字符串使用string,同时引用相应头文件
string S_name;
//id
int S_studentcard;
void S_showname()
{
cout << "学生的名字是" <<S_name << endl;
}
void S_showcard()
{
cout << "学生的学号是" << S_studentcard << endl;
}
};
int main()
{
Student ZZM;
//字符串使用双引号,单字符使用单引号
ZZM.S_name = "张泽明";
ZZM.S_studentcard = 2023;
ZZM.S_showcard();
ZZM.S_showname();
system("pause");
return 0;
}
设计类时,可以把属性和行为放在不同的权限下,加以控制
cpp
//三种访问权限:public(公共权限)protected(保护权限)private(私有权限)
//public 成员类内可以访问,类外也可以访问
//protected 类内可以访问 类外不可以访问
//private 类内可以访问 类外不可以访问
//后两个在继承里面体现出区别看,子类可以访问父类中的保护内容,不可以访问私有内容
class person
{
public:
string M_name;
private:
string M_passport;
protected:
string M_ID;
public:
void func()
{
//类内可以访问
M_ID = "123456";
M_name = "zhangsan";
M_passport = "123123";
}
};
int main()
{
//实例化对象
person p1;
p1.M_name = "nima";
// 这类内容是访问不到的
// p1.M_ID = "goode";
//函数也一样
p1.func();
system("pause");
return 0;
}
在C++中class和struct默认的访问权限不同
struct默认权限是 public
class默认权限是 private
默认权限就是,不进行权限设置,属性和行为的访问权限
权限设置技巧
cpp
class Person
{
public:
//通过行为的设置进行信息的读取
void setname(string name)
{
string M_name = name;
}
string getname()
{
return M_name;
}
private:
//将属性放置在私有权限内
string M_name;
string M_car;
string M_id;
};
函数传入一个实例的格式
bool func(cube& c)
{
}
构造函数和析构函数:
cpp
//构造函数和析构函数是为了完成对象的初始化和清理操作
//如果我们不提供,编译器会自动提供(空实现)
//对象的初始化和清理
class person
{
//1.构造函数,对象的初始化操作
//没有返回值 不用写void
//函数名与类名相同
//构造函数可以有参数,可以发生重载
//创建对象时,构造函数会自动调用,且只调用一次
person()
{
}
//2.析构函数 进行清理操作
//没有返回值,不写void
//函数名与类名相同 在名称前加上~
//析构函数不存在参数,不能发生重载
//对象在销毁前 会自动调用析构函数,而且只会调用一次
~person()
{
}
//system("pause")就是在这一步停止的意思
};
构造函数的分类和调用
cpp
//构造函数:
//两种分类方式:
//按参数分为:有参构造和无参构造
//按类型分为:普通构造和拷贝构造
//三种调用方式:
//括号法 显示法 隐式转换法
//分类
class person
{
public:
//构造函数
person()//无参
{
}
person(int a)//有参
{
}
//拷贝构造函数
person(const person &p)
{
}
//析构函数
~person()
{
}
};
//构造函数的调用
int main()
{
//1.括号法
person p1;//无参
person p2(10);//有参
person p3(p2);//拷贝函数
//注意事项,调用无参构造函数时,不要加()因为会被认为是一个函数声明
//2.显示法
person p4;
person p5 = person(10);//有参
person p6 = person(p5);//拷贝构造
person(10);//匿名对象,执行此行之后,系统会立刻回收该对象
//注意事项:不要利用拷贝构造函数初始化匿名对象,因为其相当于进行实例化
//3.隐式转换法
person p7 = 10;//相当于 person p7 = person(10);
system("pause");
return 0;
}
拷贝函数调用时机
cpp
//通常有三种调用情况
class person
{
public:
int M_age;
person()
{
cout << "无参构造函数调用" << endl;
}
person(int a)
{
cout << "有参构造函数调用" << endl;
}
person(const person& p)
{
cout << "拷贝构造函数调用" << endl;
}
~person()
{
cout << "析构函数调用" << endl;
}
};
//1.使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
person p1 (20);
person p2(p1);
cout << p2.M_age << endl;
}
//2.值传递的方式给函数参数传值
void work(person p)
{
}
void test02()
{
person p;
//这里调用一个拷贝函数,创建新的数据传入work
work(p);
}
//3值方式返回局部对象
person work2(person p)
{
person p1;
//调用拷贝函数,返回局部变量的值
return p1;
}
构造函数的调用规则:
cpp
//默认情况下,编译器会给一个类添加三个函数
//1.默认构造函数(无参,函数体为空)
//2.默认析构函数(无参,函数体为空)
//3.默认拷贝构造函数,对属性进行值拷贝
//构造函数调用规则:
//如果用户定义有参构造函数,编译器不再提供默认无参构造函数,但是会提供默认拷贝函数(没有默认构造函数,调用报错)
//如果用户定义拷贝构造函数,编译器不会再提供其他构造函数(同理)
深拷贝与浅拷贝
cpp
//浅拷贝:简单的拷贝赋值操作
//深拷贝:在堆区重新申请空间,进行拷贝操作
class person
{
public:
person()
{
cout << "无参构造函数调用" << endl;
}
person(int age, int height)
{
m_age = age;
int* m_height = new int(height);
cout << "有参构造函数调用" << endl;
}
person(const person& p)
{
m_age = p.m_age;
//m_height = p.m_height;编译器实现这行代码的时候,会导致堆区数据被重复释放,所以要重新申请重新使用
int m_height = new int(*p.m_height);
}
~person()
{
//析构代码,将堆区开辟数据做释放操作
if (m_height!=NULL)
{
delete m_height;
m_height = NULL;
}
}
int m_age;
int* m_height;
};
初始化列表
cpp
//c++的初始化列表
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;
};
类对象作为类成员
cpp
//类对象作为类成员
//构造函数:先调用成员的构造函数
//析构函数:先调用自身的析构函数
class phone
{
public:
phone(string pname)
{
p_name = pname;
}
string p_name;
};
class person
{
public:
//这里类似于隐式转换 phone p = p_name;
person(string age, string p_name) :m_age(age), p(p_name)
{
}
int m_age;
phone p;
};
静态成员:
cpp
class person
{
public:
//静态成员
//所有成员使用一个数据
//编译时就分配内存
//类内声明,类外初始化
static int m_A;
//静态成员同样具有访问权限
private:
static int m_b;
};
//类外初始化 person:: 代表person下的成员
int person::m_A = 10;
int person::m_b = 20;
void test01()
{
//静态成员的两种访问方式
//通过对象进行访问
person p;
cout << p.m_A << endl;
//通过类进行访问
cout << person::m_A << endl;
}
静态函数
cpp
//静态函数
//所有对象共享一个函数
//静态函数只能访问静态成员变量
class person
{
//静态函数同样存在权限访问问题
public:
static void func()
{
m_a = 20;
//m_b = 20;不能访问该变量
}
static int m_a;
int m_b;
};
int person::m_a = 10;
void func()
{
//两种访问方式
person p;
p.func();
//类名访问
person::func();
}
成员变量和成员函数分开存储:
cpp
class person
{
//空对象大小是1
//c++编译器会给每个空对象分配一个字节空间,为了区分空对象占内存的位置
//非静态成员变量属于类上
int m_a;
//静态成员变量不属于类上
static int m_b;
//非静态成员函数不属于类上
void func(){}
//静态成员函数不属于类上
static void func(){}
};
int person::m_b = 10;
void test01()
{
person p;
cout << sizeof(p) << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
this指针:
cpp
//this指针的作用(每个非静态成员函数都有,不用定义直接调用)
//1.解决名称冲突,当形参和变量名称一样时
class person
{
public:
person(int age)
{
//this指向的是被调用成员函数所属的对象,就是创建的person p
this->age = age;
}
//这里使用person的引用才能对创建的对象进行数据修改,不然就是简单的数据拷贝不能叠加
person& addage(person p)
{
this->age += p.age;
//返回对象本身使用*this
return *this;
}
int age;
};
//2.返回对象本身用*this
void test01()
{
person p1(10);
person p2(10);
//链式编程思想
p1.addage(p2).addage(p2).addage(p2);
}
空指针访问成员函数:
cpp
class person
{
public:
void func()
{
//一般这里会隐形地给出this->m_age,因此使用空指针指向这个函数就会出现问题
//使用if判断一下,为空就直接return
cout << m_age << endl;
}
int m_age=18;
};
void test01()
{
person *p=NULL;
p->func();
}
int main()
{
test01();
return 0;
}
常函数:
cpp
class person
{
//const本质上是修饰的this指针常量,使得指针常量指向的值也不能修改
void func()const
{
this->m_a = 10;
this->m_b = 10;
}
int m_a;
mutable int m_b;//被mutable修饰的量可以在常函数中进行修改
};
常对象:
cpp
void test01()
{
//常对象不能修改成员属性
//mutable修饰的可以修改
const person p1;
//常对象不能调用普通成员函数,能调用常函数
}
全局函数作友元:
cpp
//友元使对象可以访问private的属性数据
class Building
{
//friend 放在函数前面
friend void test01(Building* B);
public:
string livingroom;
private:
string bedroom;
public:
Building()
{
livingroom = "kt";
bedroom = "ws";
}
};
void test01(Building *B)
{
cout << B->livingroom << endl;
cout << B->bedroom << endl;
}
类作友元:
cpp
class Building
{
friend class goodgay;
public:
//在类外写函数,类内的函数就不能有函数体包括大括号{}
Building() ;
string livingroom;
private:
string bedroom;
};
class goodgay
{
public:
goodgay() ;
void visit() ;
private:
Building* building;
};
Building::Building()
{
livingroom = "keting";
bedroom = "woshi";
}
goodgay::goodgay()
{
building = new Building;
}
//注意类外写函数的格式
void goodgay::visit()
{
cout << building->bedroom<<endl;
cout << building->livingroom<<endl;
}
void test01()
{
goodgay g1;
g1.visit();
}
int main()
{
test01();
system("pause");
return 0;
}
成员函数作友元:
cpp
friend goodgay::visit();
运算符重载的格式实际上就是函数的格式再稍微改变一下
加号运算符重载:
cpp
//运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
//运算符重载也能发生函数重载
//1.成员函数作运算符重载
class person
{
public:
person(int a, int b)
{
m_A = a;
m_B = b;
}
person operator+(person& p)
{
this->m_A += p.m_A;
this->m_B += p.m_B;
return *this;
}
int m_A ;
int m_B ;
};
//2.全局函数作运算符重载
person operator+(person& p1, person& p2)
{
person temp(0,0);
temp.m_A = p1.m_A + p2.m_A;
temp.m_B = p1.m_B + p2.m_B;
}
void test01()
{
person p1(10, 10);
person p2(10, 10);
person p3(0, 0);
p3 = p1 + p2;
cout << p3.m_A << endl << p3.m_B<<endl;
}
int main()
{
test01();
system("pause");
return 0;
}
移位运算符重载:
cpp
//cout是ostream类的一个对象
//不能使用成员函数进行移位运算符重载,因为产生不了相应的效果
class person
{
public:
friend ostream& operator<<(ostream& cout, person& p);
person(int a,int b)
{
m_a = a;
m_b = b;
}
private:
int m_a;
int m_b;
};
//返回值为ostream&,符合链式编程思想
ostream& operator<<(ostream& cout, person& p)
{
cout << p.m_a << p.m_b;
return cout;
}
void test01()
{
person p1(10, 10);
cout << p1 << endl;
}
递增运算符重载:
cpp
//成员函数实现递增运算符重载
class intage
{
friend ostream& operator<<(ostream& cout, intage i);
public:
intage(int a)
{
m_num = a;
}
//前置递增
//必须使用intage&,不然就会出问题
intage& operator++()
{
m_num++;
return*this;
}
//占位参数实现后置递增,加上一个int代表后置递增
//这里必须使用intage,因为返回的temp是局部变量,会被释放掉,不过还是会出问题
intage operator++(int)
{
int temp = m_num;
m_num++;
return temp;
}
private:
int m_num;
};
//全局函数实现<<重载
ostream& operator<<(ostream&cout,intage i)
{
cout << i.m_num;
return cout;
}
void test01()
{
intage in = 10;
cout << ++(++in) << endl;
cout << in << endl;
cout << (in++)++<< endl;
cout << in<< endl;
}
int main()
{
test01();
system("pause");
return 0;
}
赋值运算符重载:
cpp
//c++编译器会给一个类添加一共四个函数
//默认构造函数,默认析构函数,默认拷贝构造函数
//赋值运算符 operator=,对属性进行值拷贝
//可以解决浅拷贝导致的指针重复释放的问题
关系运算符重载(大于 小于 不等于 等于==)
跟前几个差不多
函数调用运算符重载,就是()
在类中重载的(),被称为仿函数,也跟上面的差不多
继承:
利用继承,可以减少重复代码
cpp
//继承语法:class 子类:继承方式 父类
class base
{
public:
void b()
{
cout << 123 << endl;
}
};
class child :public base
{
};
继承方式:
子类的对象模型:
cpp
class base
{
public:
int m_a;
//private仍然被继承下来,但是被隐藏,没法调用
private:
int m_b;
protected:
int m_c;
};
class son :public base
{
public:
int m_d;
};
void test01()
{
//结果是16,子类会继承父类中的所有数据
cout << sizeof(son) << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
构造和析构的顺序:
先构造父类,再构造子类,析构相反
继承中,同名成员处理方式
cpp
class base
{
public:
void func() {};
void func(int a)
{
cout << a << endl;
};
int m_a;
};
class son :public base
{
public:
void func() {};
int m_a;
};
void test01()
{
son s;
//调用子类,直接调用
s.m_a;
s.func();
//调用父类,就加作用域即可
s.base::func(100);
s.base::m_a;
}
int main()
{
test01();
system("pause");
return 0;
}
同名静态成员的处理方式:
cpp
//同名静态成员属性
class base
{
public:
static int m_a;
};
int base::m_a = 100;
class son :public base
{
public:
static int m_a;
};
int son::m_a = 50;
void test01()
{
//1.通过作用域访问
//2.通过类名进行访问
cout << son::m_a << endl;
cout << son::base::m_a << endl;
//静态成员函数也一样
}
继承的语法:
cpp
//多继承
class son :public base1, public base2
{
};
菱形继承:
两个类同时继承自一个类,再同时继承给一个子类,那么该子类对于第一个类的数据继承了两份
cpp
class animal
{
public:
int m_a;
};
//利用虚继承解决菱形继承问题
//虚继承,继承一个指针列表,指向该数据(大概)
class sleep:virtual public animal{};
class tuo:virtual public animal{};
class sleeptuo:public sleep,public tuo{};
void test01()
{
sleeptuo st;
//不会报错
st.m_a;
}
多态:
cpp
//静态多态:函数重载 运算符重载属于静态多态
//动态多态:派生类和虚函数实现运行时多态
//二者区别:
//静态多态:函数地址早绑定 编译阶段确定函数地址
//动态多态:函数地址晚绑定 运行阶段确定函数地址
//多态满足条件:1.有继承关系2.子类重写父类中的虚函数
//多态使用条件:父类指针或引用指向子类对象
class animal
{public:
//添加virtual使地址晚绑定,传入参数之后再绑定,使speak处于多种状态
virtual void speak()
{
cout << 1;
}
};
class cut :public animal
{
public:
void speak()
{
cout << 2;
}
};
class dog :public animal
{
public:
void speak()
{
cout << 3;
}
};
void dospeak( animal& animal)
{
animal.speak();
}
void test()
{
cut c;
dospeak(c);
dog d;
dospeak(d);
}
int main()
{
test();
system("pause");
return 0;
}
多态实现计算机类
cpp
#include<iostream>
using namespace std;
#include<string>
//利用多态实现计算机类
// 开闭原则:多扩展进行开放,对修改进行关闭
//多态的好处:
//1.组织更加清晰
//2.可读性强
//3.利于前期和后期的维护
//创建一个计算机的抽象类
class AbstrateCalcultor
{
public:
virtual int getResult()
{
return 0;
}
int Num1=0;
int Num2=0;
};
//加法类
class AddCalcultor :public AbstrateCalcultor
{
int getResult()
{
return Num1 + Num2;
}
};
//减法类
class SubCalcultor :public AbstrateCalcultor
{
int getResult()
{
return Num1 - Num2;
}
};
//乘法类
class MutiCalcultor :public AbstrateCalcultor
{
int getResult()
{
return Num1 * Num2;
}
};
void test01()
{
AbstrateCalcultor* abs = new AddCalcultor;
abs->Num1 = 1;
abs->Num2 = 2;
cout << abs->Num1 << "+" << abs->Num2 << "=" << abs->getResult() << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
纯虚函数和抽象类
cpp
class base
{
public:
//类中只要有一个纯虚函数,就被称为抽象类
//纯虚函数
virtual void func() = 0;
//抽象类的特点:
//1.无法实例化对象
//2.子类必须重写父类中的纯虚函数,否则也无法实例化对象
};
class son :public base
{
public:
virtual void func()
{
cout << "abs" << endl;
}
};
虚析构和纯虚析构
cpp
//虚析构和纯虚析构
//为了解决父类指针释放子类对象的问题
//子类出现开辟数据然后释放的操作时需要
//存在纯虚析构函数的类也称为抽象类
class Animal
{
public:
virtual void speak() = 0;
Animal()
{
cout << 1 << endl;
}
//虚析构
virtual ~Animal()
{
cout << 2 << endl;
}
//纯虚析构,需要在外面实现一下
virtual ~Animal() = 0;
};
Animal::~Animal()
{
}
class Cat :public Animal
{
public:
virtual void speak()
{
cout << *Name << "在说话" << endl;
}
Cat(string C_Name)
{
Name = new string(C_Name);
cout << 3 << endl;
}
~Cat()
{
cout << 4 << endl;
if (Name != NULL)
{
delete Name;
Name = NULL;
}
}
string* Name;
};
void test01()
{
Animal* an = new Cat("name");
an->speak();
//delete的是父类指针,无法进入子类虚构代码,因此使用虚析构
delete an;
}
int main()
{
test01();
system("pause");
return 0;
}
//析构函数的调用时机:创建实例向其中传值或者其他实例的时候
//析构函数的调用时机:销毁实例或者数据的时候
文件操作
cpp
//程序运行时产生的数据属于临时数据,运行结束就会被释放掉,通过文件可以将数据永久化
//使用文件要包含头文件文件流<fstream>
//文件类型:
//1,文本文件:以文本的ASCII形式存储
//2,二进制文件:文本以二进制形式存储,一般不能直接读取
//操作文件的三大类:
//1.ofstream 写操作
//2.ifstream 读操作
//3.fstream 读写操作
写文件:
cpp
//1.包含头文件
#include<fstream>
//2.创建流对象(写操作)
ofstream ofs;
void test()
{
//3.打开文件
ofs.open("666.txt", ios::out);
//4.写文件
ofs << "123" << endl;
ofs << "456" << endl;
ofs << "789" << endl;
//5.关闭文件
ofs.close();
}
int main()
{
test();
system("pause");
return 0;
}
读文件:
cpp
#include<fstream>
//读文件
ifstream ifs;
void test()
{
ifs.open("666.txt", ios::in);
//判断是否读取成功
if (!ifs.is_open())
{
cout << "读取失败" << endl;
}
//三种读取数据的方式
// 一行一行地读的
//
char buf[1024] = { 0 };
while (ifs >> buf)
{
cout << buf << endl;
cout << 1;
}
//
char buf[1024] = { 0 };
while (ifs.getline(buf, sizeof(buf)))
{
cout << buf << endl;
cout << 1;
}
//
string buf;
while (getline(ifs, buf))
{
cout << buf << endl;
}
//关闭文件
ifs.close();
}
int main()
{
test();
system("pause");
return 0;
}
二进制文件:
写文件
cpp
#include<fstream>
class Person
{
public:
char Name[64];
int Age;
};
//创建流对象和打开文件可以写在同一个地方
ofstream ofs("write.txt", ios::out | ios::binary);
void test()
{
Person p = { "张三",18};
//写文件
ofs.write((const char*)&p,sizeof(&p));
ofs.close();
}
int main()
{
test();
return 0;
}
读文件
cpp
#include<fstream>
class Person
{
public:
char Name[64];
int Age;
};
ifstream ifs;
void test()
{
Person p;
ifs.open("write.txt", ios::in | ios::binary);
//判断是否读取成功
if (!ifs.is_open())
{
}
ifs.read(( char*) & p, sizeof(Person));
cout <<p.Name << endl << p.Age << endl;
}
int main()
{
test();
system("pause");
return 0;
}