主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓
目录
一、内存分区模型
1.程序运行前
代码区:
全局区:
2.程序运行后
栈区:
堆区:
3.new操作符
二、引用
1.引用的基本使用和注意事项
2.引用做函数参数
3.引用做函数返回值
4.引用的本质
5.常量引用
三、函数提高
1.函数默认参数
2.函数占位参数
3.函数重载
1)函数重载概述
2)函数重载注意事项
四、类和对象
1.封装
1)封装的意义
2)struct和class区别
3)成员属性设置为私有
练习案例1-设计立方体类
练习案例2-点和圆的关系
2.对象的初始化和清理
1)构造函数和析构函数
2)构造函数的分类及调用
3)拷贝构造函数调用时机
4)构造函数调用规则
5)深拷贝与浅拷贝
6)初始化列表
7)类对象作为类成员
8)静态成员
3.C++对象模型和this指针
1)成员变量和成员函数分开存储
2)this指针概念
3)空指针访问成员函数
4)const修饰成员函数
4.友元
5.运算符重载
1) 加号运算符重载
2)左移运算符重载
3)递增运算符重载
4)赋值运算符重载
5)关系运算符重载
6)函数调用运算符重载
6.继承
1)继承的基本语法
2)继承方式
3)继承中的对象模型
4)继承中构造和析构顺序
5)继承同名成员处理方式
6)继承同名静态成员处理方式
7)多继承语法
8)菱形继承
7.多态
1)基本概念
2)多态案例一-计算机类
3)纯虚函数和抽象类
4)多态案例二-制作饮品
5)虚析构和纯虚析构
6)多态案例三-电脑组装
五、文件操作
1.文本文件
1)写文件
2)读文件
2.二进制文件
C++程序在执行时,将内存大方向划分为4个区域:
- 代码区:存放函数体的二进制代码,由操作系统进行管理的
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
内存四区的意义:
- 不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
不在全局区中有:
全局区:
#include
using namespace std;
//栈区数据的注意事项——不要返回局部变量的地址
//栈区的数据由编译器管理开辟和释放
int * func(int b)//形参数据也会放在栈区
{
b=100;
int a=10;//局部变量,存放在栈区 栈区的数据在函数执行完后自动释放
return &a;//返回局部变量的地址
}
int main()
{
int * p=func();
cout<<*p<
#include
using namespace std;
int * func()
{
//利用new可以将数据开辟到堆区
//指针本质也是局部变量,放在栈上,指针保留的数据放在堆区
int * p = new int(10);
return p;
}
int main()
{
//在堆区开辟数据
int * p = func();
cout<<*p<
new 数据类型
#include
using namespace std;
//1.new的基本语法
int * func()
{
// 在堆区创建整型数据
// new返回的是 该数据类型的指针
int * p=new int(10);
return p;
}
void test01()
{
int * p=func();
cout<<*p<
给变量起别名
数据类型 &别名 = 原名;
注意:
作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参
#include
using namespace std;
//交换函数
//1.值传递
void swap01(int a ,int b)
{
int temp = a;
a = b;
b = temp;
}
//2.地址传递
void swap02(int * a,int * b)
{
int temp = * a;
* a = * b;
* b = temp;
}
//3.引用传递
void swap03(int &a,int &b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a=10;int b=20;
//swap01(a,b);
//swap02(&a,&b);
swap03(a,b);
cout<<"a="<
作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量引用
用法:函数调用作为左值存在
#include
using namespace std;
//引用作函数的返回值
//1.不要返回局部变量引用
int & test01() // 用引用的方式返回
{
int a = 10;//局部变量,存放在栈区
return a;
}
int & test02()
{
static int a = 10;//静态变量,在全局区(在程序结束后由系统释放)
return a;
}
int main()
{
/*
int &ref=test01();
cout<<"ref="<
引用的本质在c++内部实现是一个指针常量
#include
using namespace std;
//发现是引用,转换为int * const ref = &a;
void func(int &ref)
{
ref=100; //ref是引用,转换为*ref=100;
}
int main()
{
int a = 10;
//自动转换为 int * const ref = &a;指针常量是指针指向不可修改,也说明为什么引用不可更改
int & ref = a;
ref = 20; //内部发现ref是引用,自动帮我们转换为:*ref = 20;
cout<<"a:"<
作用:常量引用主要用来修饰形参,防止误操作
int main()
{
//常量引用
//使用场景:用来修饰形参,防止误操作
//int a = 10;
//1.
//int & ref = 10; //引用必须引一块合法的内存空间
//2.
const int & ref = 10;
//加上const后,编译器将代码修改 int temp 10; const int & ref = temp;
//(编译器自己起的原名—temp)
//ref = 20;
//加入const之后,变为只读,不可修改
system("pause");
return 0;
}
当我们不小心在showValue函数中修改了val的值,导致a的值也被修改
#include
using namespace std;
//打印数据的函数
void showValue(int &val)
{
val = 1000;
cout<<"val="<
但我们在打印函数的参数上添加const,val会报错(表达式必须是可修改的左值) ,防止误操作
在c++中,函数的形参列表中的形参是可以有默认值的
返回值类型 函数名 ( 参数 = 默认值 ) { }
#include
using namespace std;
//函数的默认参数
int func(int a,int b = 20,int c = 30)
{
return a+b+c;
}
int main()
{
cout<
注意事项:
c++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
返回值类型 函数名 (数据类型){ }
#include
using namespace std;
//占位参数
void func(int a,int) //第二个int起到占位作用
{
cout<<"this is func"<
作用:函数名可以相同,提高复用性
函数重载满足条件:
#include
using namespace std;
//函数重载
//可以让函数名相同,提高复用性
//满足条件:
//1.同一个作用域下
//2.名称相同
//3.函数参数类型不同 / 个数不同 / 顺序不同
void func()
{
cout<<"func的调用"<
注意:
#include
using namespace std;
//函数重载注意事项
//1.引用作为函数重载的条件
void func(int& a)
{
cout<<"func(int& a)的调用"<
C++面向对象的三大特性为:封装、继承、多态
class 类名 { 访问权限: 属性 / 行为 };
类中的属性和行为 统称为 成员
属性 成员属性 成员变量
行为 成员函数 成员方法
#include
using namespace std;
const double PI = 3.14;
//设计一个圆类,求圆周长
class Circle
{
//访问权限-公共权限
public:
//属性
int m_r;
//行为-获取圆的周长
double calculateZC()
{
return 2*PI*m_r;
}
};
int main()
{
//通过圆类创建一个具体的圆-对象
Circle c1;
//给圆对象的属性进行赋值
c1.m_r=10;
cout<<"圆的周长:"<
#include
using namespace std;
#include
//设计一个学生类,属性有学号和姓名,可以给姓名和学号赋值,可以显示姓名和学号
class Student
{
public:
string m_Name;
int m_Id;
void SetName(string name)
{
m_Name=name;
}
void Write()
{
cout<<"姓名:"<>m_Name;
cout<<"学号:"<>m_Id;
}
void ShowStu()
{
cout<<"姓名:"<
三种访问权限:
唯一区别在于——默认的访问权限不同
优点:
#include
using namespace std;
#include
//成员属性设置为私有
//将所有成员属性设置为私有,可以自己控制读写权限
class Person
{
public:
//写 姓名
void setName(string name)
{
_name=name;
}
//读 姓名
string getName()
{
return _name;
}
//获取 年龄
int getAge()
{
_age=0; // 初始化为0岁
return _age;
}
//设置 爱人
void setLover(string lover)
{
_lover=lover;
}
private:
//姓名 可读可写
string _name;
//年龄 只读
int _age;
//爱人 只写
string _lover;
};
int main()
{
Person p1;
p1.setName("张三");
cout<<"姓名为:"<
#include
using namespace std;
#include
//成员属性设置为私有
//对于写权限,我们可以检测数据的有效性
class Person
{
public:
//写 姓名
void setName(string name)
{
_name=name;
}
//读 姓名
string getName()
{
return _name;
}
//获取 年龄 可读可写 如果想修改(年龄的范围必须是0~18之间)
int getAge()
{
return _age;
}
//设置年龄
void setAge(int age)
{
if(age<0||age>18)
{
_age=0; //强制改为0岁
cout<<"您的年龄不符合"<
#include
using namespace std;
//设计立方体类Cube
//求出立方体的面积和体积
//分别用全局函数和成员函数判断两个立方体是否相等
class Cube
{
public:
//设置长宽高,获取长宽高
void setL(int l)
{
m_L = l;
}
int getL()
{
return m_L;
}
void setW(int w)
{
m_W = w;
}
int getW()
{
return m_W;
}
void setH(int h)
{
m_H = h;
}
int getH()
{
return m_H;
}
//获取面积
int calculateS()
{
return 2 * m_L * m_W + 2 * m_L * m_H + 2 * m_H * m_W;
}
//获取体积
int calculateV()
{
return m_L * m_H * m_W;
}
//利用成员函数判断
bool isSameByClass(Cube& c)
{
if (m_L == c.getL() && m_W == c.getW() && m_H == c.getH())
{
return true;
}
return false;
}
private:
int m_L;
int m_W;
int m_H;
};
//利用全局函数判断 两个立方体是否相等
bool isSame(Cube& c1, Cube& c2) // 利用引用 节省内存
{
if (c1.getL() == c2.getL() && c1.getW() == c2.getW() && c1.getH() == c2.getH())
{
return true;
}
else
{
return false;
}
}
int main()
{
Cube c1;
c1.setL(10);
c1.setW(10);
c1.setH(10);
cout << "c1的面积为:" << c1.calculateS() << endl;
cout << "c1的体积为:" << c1.calculateV() << endl;
Cube c2;
c2.setL(10);
c2.setW(10);
c2.setH(10);
//利用全局函数
bool ret = isSame(c1, c2);
if (ret)
{
cout << "c1和c2相等" << endl;
}
else
{
cout << "c1和c2不相等" << endl;
}
//利用成员函数
ret = c1.isSameByClass(c2);
if (ret)
{
cout << "c1和c2相等" << endl;
}
else
{
cout << "c1和c2不相等" << endl;
}
system("pause");
return 0;
}
#include
using namespace std;
//设计一个圆类(Circle) 和 一个点类(Point),计算点和圆的关系
class Point
{
public:
void setX(int x)
{
m_X = x;
}
int getX()
{
return m_X;
}
void setY(int y)
{
m_Y = y;
}
int getY()
{
return m_Y;
}
private:
int m_X;
int m_Y;
};
class Circle
{
public:
void setR(int r)
{
m_R = r;
}
int getR()
{
return m_R;
}
void setCenter(Point center)
{
m_Center = center;
}
Point getCenter()
{
return m_Center;
}
private:
int m_R; //半径
Point m_Center; //圆心
};
//判断点和圆关系
void isInCircle(Circle &c,Point p)
{
int distance = (c.getCenter().getX() - p.getX()) ^ 2 + (c.getCenter().getY() - p.getY()) ^ 2;
int rDistance = c.getR() * c.getR();
if (distance > rDistance)
cout << "点在圆外" << endl;
else if (distance == rDistance)
cout << "点在圆上" << endl;
else
cout << "点在圆内" << endl;
}
int main()
{
Circle c1;
c1.setR(10);
Point center1;
center1.setX(10);
center1.setY(0);
c1.setCenter(center1);
Point p1;
p1.setX(10);
p1.setY(10);
isInCircle(c1, p1);
system("pause");
return 0;
}
对象的初始化和清理也是两个非常重要的安全问题
构造函数:主要作用在于创建时对对象的成员属性赋值,构造函数由编译器自动调用,无需手动
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作
构造函数语法:
类名(){ }
析构函数语法:
~类名(){ }
语法:
#include
using namespace std;
//对象的初始化和清理
class Person
{
public:
//1构造函数 初始化
//没有返回值,不写void
//函数名与类名称相同
//可以有参数,发生重载
//创建对象时,构造函数会自动调用,且只调用一次
Person()
{
cout << "Person构造函数的调用" << endl;
}
//2.析构函数 清理
//没有返回值,不写void
//函数名与类名称相同,名称前+~
//不可以有参数,不发生重载
//对象销毁前,构造函数会自动调用,且只调用一次
~Person()
{
cout << "person析构函数的调用" << endl;
}
};
//构造和析构都是必须有的实现,如果我们自己不提供,编译器会提供一个空实现的构造和析构
void test01()
{
Person p; //在栈上的数据,test01执行完毕后,释放这个对象
}
int main()
{
test01(); //test01中只创建了个对象,没有调用,系统自动调用
//Person p; //运行只有构造没有析构
//因为main函数没有实行完毕
system("pause");
return 0;
}
两种分类方式:
三种调用方法:
#include
using namespace std;
//构造函数的分类和调用
//分类
class Person
{
public:
//构造函数
Person()
{
cout << "Person无参构造函数的调用" << endl;
}
Person(int a)
{
age = a;
cout << "Person有参构造函数的调用" << endl;
}
//拷贝构造函数
Person(const Person& p) //const防止修改实参
{
//将传入的人身上的所有属性,拷贝到我身上
age = p.age;
cout << "Person拷贝构造函数的调用" << endl;
}
//析构函数
~Person()
{
cout << "Person析构函数的调用" << endl;
}
int age;
};
//调用
void test01()
{
//1.括号法
Person p1; //默认构造函数
Person p2(10); //有参构造函数
Person p3(p2); //拷贝构造函数
/*
注意:
调用默认构造函数,不要 + ()
*/
//2.显示法
Person p4;
Person p5 = Person(10);
Person p6 = Person(p5);
//Person(10);
//匿名对象 特点:当前行执行结束后,系统会立即回收掉匿名对象
//cout << "aaa" << endl;
/*
注意:
不要利用拷贝构造函数,初始化匿名对象 编译器会认为 Person(p2)=== Person p2
*/
//Person(p2);
//3.隐式转换法
Person p7 = 10; //相当于Person p7 = Person(10)
Person p8 = p8;//拷贝
}
int main()
{
test01();
system("pause");
return 0;
}
#include
using namespace std;
//拷贝构造函数调用时机
class Person
{
public:
Person()
{
cout << "Person默认构造函数调用" << endl;
}
Person(int age)
{
cout << "Person有参构造函数调用" << endl;
m_Age = age;
}
Person(const Person& p)
{
cout << "Person拷贝构造函数调用" << endl;
m_Age = p.m_Age;
}
~Person()
{
cout << "Person析构函数调用" << endl;
}
int m_Age;
};
//1.使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
Person p1(20);
Person p2(p1);
}
//2.值传递的方式给函数参数传值
void doWork(Person p)
{
}
void test02()
{
Person p;
doWork(p);
}
//3.以值方向返回局部对象
Person doWork2()
{
Person p1;
cout << (int*)&p1 << endl;
return p1;
}
void test03()
{
Person p = doWork2();
cout << (int*)&p << endl;
}
int main()
{
//test01();
//test02();
test03();
system("pause");
return 0;
}
默认情况下,c++编译器至少给一个类添加3个函数
构造函数调用规则如下:
#include
using namespace std;
class Person
{
public:
Person()
{
cout << "Person的默认构造函数调用" << endl;
}
Person(int age,int height)
{
m_Age = age;
m_Height = new int(height);
cout << "Person的有参构造函数调用" << endl;
}
//自己实现拷贝构造函数,解决 浅拷贝 带来的问题
Person(const Person& p)
{
cout << "Person拷贝构造函数的调用" << endl;
m_Age = p.m_Age;
//m_Height = p.m_Height; // 编译器默认实现就是这行代码
//深拷贝操作
m_Height = new int(*p.m_Height);
}
~Person()
{
//析构代码,将堆区开辟的数据做释放操作
if (m_Height != NULL) {
delete m_Height;
m_Height = NULL; //防止野指针出现,置空
}
cout << "Person的析构函数调用" << endl;
}
int m_Age;
int* m_Height;
};
void test01()
{
//浅拷贝带来的问题:堆区的内存重复释放
Person p1(18, 180);
cout << "p1的年龄为:" << p1.m_Age << " 身高为:" << *p1.m_Height << endl;
Person p2(p1);
cout << "p2的年龄为:" << p2.m_Age << " 身高为:" << *p2.m_Height << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
作用:
构造函数( ):属性1(值1),属性2(值2)…{ }
#include
using namespace std;
class Person
{
public:
//传统初始化操作
/*
Person(int a, int b, int c) {
m_A = a;
m_B = b;
m_C = c;
}
*/
//初始化列表初始化属性
/*
Person() :m_A(10), m_B(20), m_C(30)
{
}
*/
//更灵活
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;
};
void test01()
{
//Person p(10, 20, 30);
//Person p;
Person p(30, 20, 10);
cout << "m_A=" << p.m_A << " m_B=" << p.m_B << " m_C=" << p.m_C << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
c++类中的成员可以是另一个类的对象,我们称该成员为 对象成员
#include
using namespace std;
#include
class Phone
{
public:
Phone(string pname)
{
cout << "Phone的构造函数调用" << endl;
m_PName = pname;
}
~Phone()
{
cout << "Phone的析构函数调用" << endl;
}
string m_PName;
};
class Person
{
public:
//Phone m_Phone = pName 隐式转换法 相当于 Phone m_Phone = Phone(pName)
Person(string name,string pName):m_Name(name),m_Phone(pName) //人名,手机名
{
cout << "Person的构造函数调用" << endl;
}
~Person()
{
cout << "Person的析构函数调用" << endl;
}
string m_Name;
Phone m_Phone;
};
/*Phone的构造函数调用
Person的构造函数调用
张三拿了香蕉牌手机
Person的析构函数调用
Phone的析构函数调用*/
//当其他类对象作为本类成员,先构造其他类对象,再构造自身。
//析构顺序与构造顺序相反
void test01()
{
Person p("张三", "香蕉牌");
cout << p.m_Name << "拿了" << p.m_Phone.m_PName << "手机" << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
静态成员就是在成员变量和成员函数前加上关键字 static 称为静态成员
静态成员分为:静态成员变量、静态成员函数
#include
using namespace std;
#include
class Person
{
public:
//在编译阶段分配内存
//类内声明
static int m_A;
private:
//静态成员变量也是有访问权限的
static int m_B;
};
// 类外初始化操作
int Person::m_A = 100;
int Person::m_B = 200;
void test01()
{
Person p;
cout << p.m_A << endl; //100
Person p2;
p2.m_A = 200;
//所有对象都共享同一份数据
cout << p.m_A << endl; //200
}
void test02()
{
//静态成员变量 不属于某个对象上 所有对象都共享同一份数据
//因此静态成员变量有两种访问方式
//1.通过对象进行访问
Person p;
cout << p.m_A << endl;
//2.通过类名进行访问
cout << Person::m_A << endl;
//cout << Person::m_B << endl; //报错 不可访问,类外访问不到私有的静态成员变量
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
#include
using namespace std;
#include
//静态成员函数
//所有对象共享同一函数
//静态成员函数只能访问静态成员变量
class Person
{
public:
//静态成员函数
static void func()
{
m_A = 100; //静态成员函数可以访问静态成员变量
//m_B = 200; //报错 不可以访问非静态成员变量 无法区分到底是那个对象的m_B属性
cout << "static void func的调用" << endl;
}
//静态成员变量
static int m_A;
//非静态成员变量
int m_B;
//静态成员函数也是有访问权限的
private:
static void func2()
{
cout << "static void func2" << endl;
}
};
int Person::m_A = 0;
void test01()
{
//1.通过对象访问
Person p;
p.func();
//2.通过类名访问
Person::func();
//Person::func2(); //报错 类外访问不到私有的静态成员函数
}
int main()
{
test01();
system("pause");
return 0;
}
c++中,类内的成员变量和成员函数分开存储的
只有 非静态成员变量 才属于类的对象上
#include
using namespace std;
#include
//成员变量和成员函数 是分开存储的
class Person
{
public:
int m_A; //非静态成员变量 属于类的对象上
static int m_B; //静态成员变量 不属于类的对象上
void func() //非静态成员函数 不属于类的对象上
{ }
static void func2() //静态成员函数 不属于类的对象上
{ }
};
int Person::m_B = 0;
void test01()
{
Person p;
//空对象占用内存空间为:1
//c++编译器会给每个空对象分配一个字节空间,是为了区分空对象占内存的位置
//每个空对象也应该有一个独一无二的内存地址
cout << "size of p : " << sizeof(p) << endl;
}
//类内写入int m_A后
void test02()
{
Person p;
//加入非静态成员变量m_A后——4
//加入静态成员变量m_B后——4
//加入非静态成员函数func后——4
//加入静态成员函数func2后——4
cout << "size of p : " << sizeof(p) << endl;
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
(我们知道c++中 成员变量 和 成员函数 是分开存储的,每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。那么问题是:这一块代码是如何区分哪个对象调用自己的呢?)
c++通过提供特殊的对象指针:this指针,解决上述问题。
this指针指向被调用的成员函数所属的对象
this指针用途:
#include
using namespace std;
#include
class Person
{
public:
Person(int age)
{
//age = age; //名称冲突
//this指针指向被调用的成员函数所属对象
this->age = age;
}
Person& PersonAddAge(Person& p) //void改Persin& 用引用的方式返回本体
{
this->age += p.age;
//this指向p3的指针,而*this指向的就是p3这个对象本体
return *this;
}
int age;
};
//1.解决名称冲突
void test01() {
Person p1(18);
cout << "p1的年龄:" << p1.age << endl; //p1的年龄:-858993460
//加入this指针后,结果正确为:18
}
//2.返回对象本身用*this
void test02() {
Person p2(10);
Person p3(10);
//p3.PersonAddAge(p2);
//cout << "p3的年龄:" << p3.age << endl;
//链式编程思想
p3.PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p2);
cout << "p3的年龄:" << p3.age << endl;
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
c++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
若用到this指针,需要加以判断保证代码的健壮性
常函数:
常对象:
#include
using namespace std;
#include
//常函数
class Person
{
public:
//this指针的本质 是指针常量:指针指向不可修改
//相当于Person * const this;
//再加const:即const Person * const this; 指针指向的值不可修改 此处加上的const相当于下一行加上的const
void showPerson() const //加const修饰的是this指针,让指针指向的值也不可以修改
{
//m_A = 100; //报错 加了const后属性不允许修改
//上句相当于this->m_A=100; //函数体自带this
//this = NULL; //报错 指向不可修改
m_B = 199; //可以修改 加过了mutable
}
void func() {
}
int m_A;
mutable int m_B; //特殊变量,即使再常函数中,也可以修改这个值
};
void test01()
{
Person p;
}
//常对象
void test02() {
const Person p1; //常对象 不允许修改指针指向的值
//p1.m_A = 0; //报错 不可修改
p1.m_B = 0; //特殊 可修改
p1.showPerson();
p1.showPerson(); //可调用
//p1.func(); //报错 常对象只可以调用常函数
//常对象不可以调用普通成员函数 因为普通成员函数可以修改属性 违背协定
}
int main()
{
test01();
system("pause");
return 0;
}
生活中你家有客厅(public) 有你的卧室(private)
客厅所有来的客人都可以进,但卧室私有,只有你能进
但是,你也可以允许你的好朋友进去
#include
using namespace std;
#include
//全局函数做友元
//建筑物类
class Building
{
//GoodFriend全局函数是Building好朋友,可以访问Building中私有成员
friend void GoodFriend(Building* building);
public:
Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
public:
string m_SittingRoom;
private:
string m_BedRoom;
};
//全局函数
void GoodFriend(Building *building)
{
cout << "好朋友的全局函数正在访问:" << building->m_SittingRoom << endl; //公有属性可以访问
//cout << "好朋友的全局函数正在访问:" << building->m_BedRoom << endl; //私有不可访问 报错
cout << "好朋友的全局函数正在访问:" << building->m_BedRoom << endl; //加friend后可以访问
}
void test01() {
Building building;
GoodFriend(&building);
}
int main()
{
test01();
system("pause");
return 0;
}
#include
using namespace std;
#include
//类做友元
class Building;
class goodGay {
public:
GoodFriend();
void visit();
public:
Building* building;
};
class Building {
//告诉编译器 GoodFriend类是Building类的好朋友,可以访问Building中私有内容
friend class GoodFriend;
public:
Building();
public:
string m_SittingRoom;
private:
string m_BedRoom;
};
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
GoodFriend::GoodFriend() {
building = new Building;
}
void GoodFriend::visit() {
cout << "好朋友正在访问" << building->m_SittingRoom << endl;
cout << "好朋友正在访问" << building->m_BedRoom << endl;
}
void test01() {
GoodFriend f1;
f1.visit();
}
int main() {
test01();
system("pause");
return 0;
}
#include
using namespace std;
#include
//成员函数做友元
class Building;
class goodGay
{
public:
goodGay();
void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
void visit2();
private:
Building* building;
};
class Building
{
//告诉编译器 goodGay类中的visit成员函数 是Building好朋友,可以访问私有内容
friend void goodGay::visit();
public:
Building();
public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
};
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
goodGay::goodGay()
{
building = new Building;
}
void goodGay::visit()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void goodGay::visit2()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
//cout << "好基友正在访问" << building->m_BedRoom << endl;
}
void test01()
{
goodGay gg;
gg.visit();
}
int main() {
test01();
system("pause");
return 0;
}
#include
using namespace std;
#include
//加号运算符重载
class Person
{
public:
//通过自己写成员函数,实现两个对象相加属性后返回新对象
/*
Person PersonAdd(Person& p) {
Person temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}
*/
//编译器给起了一个通用名称 operator+
//1.通过成员函数重载+号
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;
}
int m_A;
int m_B;
};
/*
//2.通过全局函数重载+号
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;
}
*/
//3.运算符重载 可以发生函数重载
Person operator+(Person& p2, int val)
{
Person temp;
temp.m_A = p2.m_A + val;
temp.m_B = p2.m_B + val;
return temp;
}
/*
void test01() {
Person p1;
p1.m_A = 10;
p1.m_B = 5;
Person p2;
p2.m_A = 10;
p2.m_B = 5;
Person p3 = p2.PersinAdd(p1);
cout << p3.m_A <<'\t'<< p3.m_B << endl;
}
*/
//成员函数调用
void test02() {
Person p1;
p1.m_A = 10;
p1.m_B = 5;
Person p2;
p2.m_A = 10;
p2.m_B = 5;
//Person p3 = p1.operator+(p2); //本质
Person p3 = p1 + p2; //简化形式
cout << p3.m_A << '\t' << p3.m_B << endl;
}
//全局函数调用
/*
void test03() {
Person p1;
p1.m_A = 10;
p1.m_B = 5;
Person p2;
p2.m_A = 10;
p2.m_B = 5;
Person p3 = operator+(p1, p2);
cout << p3.m_A << '\t' << p3.m_B << endl;
}
*/
void test04() {
Person p1;
p1.m_A = 10;
p1.m_B = 5;
Person p4 = p1 + 10;
cout << p4.m_A << '\t' << p4.m_B << endl;
}
int main()
{
//test01();
//test02();
//test03();
test04();
system("pause");
return 0;
}
作用:可以输出自定义数据类型
#include
using namespace std;
#include
//左移运算符重载
class Person {
friend ostream& operator<<(ostream& out, Person& p);
public:
Person(int a, int b)
{
this->m_A = a;
this->m_B = b;
}
//成员函数 实现不了 p << cout 不是我们想要的效果
//void operator<<(Person& p){
//}
private:
int m_A;
int m_B;
};
//全局函数实现左移重载
//ostream对象只能有一个
ostream& operator<<(ostream& cout, Person& p) {
cout << "a:" << p.m_A << " b:" << p.m_B;
return cout;
}
void test() {
Person p1(10, 20);
cout << p1 << " hello world" << endl; //链式编程
}
int main() {
test();
system("pause");
return 0;
}
作用: 通过重载递增运算符,实现自己的整型数据
#include
using namespace std;
#include
//递增运算符重载
class MyInteger {
friend ostream& operator<<(ostream& out, MyInteger myint);
public:
MyInteger() {
m_Num = 0;
}
//前置++
MyInteger& operator++() {
//先++
m_Num++;
//再返回
return *this;
}
//后置++
MyInteger operator++(int) {
//先返回
MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;
m_Num++;
return temp;
}
private:
int m_Num;
};
ostream& operator<<(ostream& out, MyInteger myint) {
out << myint.m_Num;
return out;
}
//前置++ 先++ 再返回
void test01() {
MyInteger myInt;
cout << ++myInt << endl;
cout << myInt << endl;
}
//后置++ 先返回 再++
void test02() {
MyInteger myInt;
cout << myInt++ << endl;
cout << myInt << endl;
}
int main() {
test01();
//test02();
system("pause");
return 0;
}
c++编译器至少给一个类添加4个函数
1. 默认构造函数(无参,函数体为空)
2. 默认析构函数(无参,函数体为空)
3. 默认拷贝构造函数,对属性进行值拷贝
4. 赋值运算符 operator=, 对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
#include
using namespace std;
#include
//赋值运算符重载
class Person
{
public:
Person(int age) {
m_Age = new int(age);
}
~Person() {
if (m_Age != NULL) {
delete m_Age;
m_Age = NULL;
}
}
//重载 赋值运算符
Person& operator=(Person& p)
{
//编译器提供浅拷贝
//m_Age = p.m_Age;
//应该先判断是否有属性在堆区,应该先释放干净,然后再浅拷贝
if (m_Age != NULL) {
delete m_Age;
m_Age = NULL;
}
m_Age = new int(*p.m_Age); //深拷贝操作
//返回自身
return *this;
}
int* m_Age;
};
void test01() {
Person p1(18);
Person p2(20);
Person p3(30);
p3 = p2 = p1; //赋值操作
//p2=p1 返回值是void p3=void 出错
cout << "p1的年龄为:" << *p1.m_Age << endl;
cout << "p2的年龄为:" << *p2.m_Age << endl;
cout << "p3的年龄为:" << *p3.m_Age << endl;
}
int main()
{
test01();
/*
int a = 10;
int b = 20;
int c = 30;
c = b = a;
cout << "a= " << a << endl; //a = 10
cout << "b= " << b<< endl; //b = 10
cout << "c= " << c << endl; //c = 10
*/
system("pause");
return 0;
}
#include
using namespace std;
#include
//关系运算符重载
class Person
{
public:
Person(string name, int age) {
m_Name = name;
m_Age = age;
}
//重载 == 号
bool operator==(Person& p) {
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
return true;
}
else return false;
}
//重载 != 号
bool operator!=(Person& p) {
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
return false;
}
else return true;
}
string m_Name;
int m_Age;
};
void test01() {
Person p1("Tom", 18);
Person p2("Tom", 18);
if (p1 == p2) {
cout << "p1和p2相等" << endl;
}
else {
cout << "p1和p2不相等" << endl;
}
if (p1 != p2) {
cout << "p1和p2不相等" << endl;
}
else {
cout << "p1和p2相等" << endl;
}
}
int main()
{
test01();
system("pause");
return 0;
}
* 函数调用运算符 () 也可以重载
* 由于重载后使用的方式非常像函数的调用,因此称为仿函数
* 仿函数没有固定写法,非常灵活
#include
using namespace std;
#include
//函数调用运算符重载
//打印输出类
class MyPrint
{
public:
//重载函数调用运算符
void operator()(string test) {
cout << test << endl;
}
};
void MyPrint02(string test) {
cout << test << endl;
}
void test01() {
MyPrint myprint;
myprint("hello world"); //重载()使用
//由于使用起来非常类似于函数调用 因此称为仿函数
MyPrint02("hello world"); //函数调用
}
//仿函数非常灵活 没有固定写法
//加法类
class MyAdd
{
public:
int operator()(int num1,int num2) {
return num1 + num2;
}
};
void test02() {
MyAdd myadd;
int num = myadd(1, 2);
cout << "num = " << num << endl;
//匿名函数对象
cout << MyAdd()(100, 100) << endl;
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
继承是面向对象三大特征之一
class 子类 : 继承方式 父类
子类 也称 派生类
父类 也称 基类
#include
using namespace std;
#include
//继承实现页面
//公共页面类
class BasePage
{
public:
void header() {
cout << "首页、公开课……(公共头部)" << endl;
}
void footer() {
cout << "帮助中心、交流合作……(公共底部)" << endl;
}
void left() {
cout << "Java、Python、C++……(公共分类列表)" << endl;
}
};
//Java页面
class Java :public BasePage
{
public:
void content() {
cout << "Java学科视频" << endl;
}
};
//Python页面
class Python :public BasePage
{
public:
void content() {
cout << "Python学科视频" << endl;
}
};
//C++页面
class Cpp :public BasePage
{
public:
void content() {
cout << "Cpp学科视频" << endl;
}
};
void test01() {
cout << "Java下载视频页面如下:" << endl;
Java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
cout << "---------------------------------- " << endl;
cout << "Python下载视频页面如下:" << endl;
Python py;
py.header();
py.footer();
py.left();
py.content();
cout << "---------------------------------- " << endl;
cout << "C++下载视频页面如下:" << endl;
Cpp cpp;
cpp.header();
cpp.footer();
cpp.left();
cpp.content();
}
//继承好处:减少重复代码
int main() {
test01();
system("pause");
return 0;
}
问:从父类继承过来的成员,哪些属于子类对象中?
#include
using namespace std;
#include
//继承中的对象模型
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son :public Base
{
public:
int m_D;
};
void test01() {
cout << "size of Son = " << sizeof(Son) << endl; //16
//在父类中所以非静态成员属性都会被子类继承下去
//父类中私有成员属性 是被编译器给隐藏了 因此访问不到 但是确实被继承下去了
}
//利用开发人员命令提示工具查看对象模型
//跳转盘符 F:
//跳转文件路径 cd 具体路径下
//查看命名
//cl /dl reportSingleClassLayout类名 文件名
int main() {
test01();
system("pause");
return 0;
}
子类继承父类后,当创建子类对象,也会调用父类的构造函数
先构造父类 再构造子类 析构与构造顺序相反
#include
using namespace std;
#include
//继承中构造和析构顺序
class Base
{
public:
Base() {
cout << "Base构造函数" << endl;
}
~Base() {
cout << "Base析构函数" << endl;
}
};
class Son :public Base
{
public:
Son() {
cout << "Son构造函数" << endl;
}
~Son() {
cout << "Son析构函数" << endl;
}
};
void test01() {
//Base b;
Son s; //子类会创建父类的对象 并调用父类的构造和析构
/*
Base构造函数
Son构造函数
Son析构函数
Base析构函数
*/
}
int main() {
test01();
system("pause");
return 0;
}
(当子类和父类 出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢)
#include
using namespace std;
#include
class Base
{
public:
Base() {
m_A = 100;
}
void func() {
cout << "Base-func()调用" << endl;
}
void func(int a) {
cout << "Base-func(int a)调用" << endl;
}
int m_A;
};
class Son :public Base
{
public:
Son() {
m_A = 200;
}
void func() {
cout << "Son-func()调用" << endl;
}
int m_A;
};
//同名成员属性
void test01() {
Son s1;
cout << "m_A = " << s1.m_A << endl; //200
cout << "m_A = " << s1.Base::m_A << endl; //加作用域 访问父类中同名成员
}
//同名成员函数
void test02() {
Son s2;
s2.func();
s2.Base::func(); //加作用域 访问父类中的同名成员函数
//如果子类中出现了和父类同名的同名函数,子类的同名成员会隐藏掉 所有 父类中所有的同名函数
//s2.func(100);//出错
//
//如果像访问到父类中被隐藏的同名成员函数 加作用域
s2.Base::func(100);
}
int main() {
//test01();
test02();
system("pause");
return 0;
}
(继承中同名的静态成员在子类对象上如何进行访问?)
静态成员和非静态成员出现同名 处理方式一致
#include
using namespace std;
#include
//继承中同名静态成员处理方式
class Base
{
public:
static void func() {
cout << "Base-func()调用" << endl;
}
static void func(int a) {
cout << "Base-func(int a)调用" << endl;
}
static int m_A;
};
int Base::m_A = 100;
class Son :public Base
{
public:
Son() {
m_A = 200;
}
static void func() {
cout << "Son-func()调用" << endl;
}
static int m_A;
};
int Son::m_A = 200;
//同名静态成员属性
void test01() {
Son s1;
//1.通过对象访问
cout << "通过对象访问 " << endl;
cout << "Son - m_A = " << s1.m_A << endl; //200
cout << "Base - m_A = " << s1.Base::m_A << endl; //100
//2.通过类名访问
cout << "通过类名访问 " << endl;
cout << "Son - m_A = " << Son::m_A << endl; //200
cout << "Base - m_A = " << Son::Base::m_A << endl; //100
}
//同名静态成员函数
void test02() {
Son s2;
//1.通过对象访问
cout << "通过对象访问 " << endl;
s2.func();
s2.Base::func();
//2.通过类名访问
cout << "通过类名访问 " << endl;
Son::func();
Son::Base::func();
//子类出现和父类 同名静态成员函数 也会隐藏父类中所有同名成员函数
//如果想访问父类中被隐藏同名成员 加作用域
//Son::func(100); //出错
Son::Base::func(100);
}
int main() {
//test01();
test02();
system("pause");
return 0;
}
c++允许一个类继承多个类
class 子类 : 继承方式 父类1,继承方式 父类2……
多继承可能会引发父类中有同名车关于出现 需要加作用域区分(实际开发中,不建议用多继承)
概念:
问题:
#include
using namespace std;
#include
//动物类
class Animal
{
public:
int m_Age;
};
//利用虚继承 可以解决菱形继承的问题
// 继承之前 加上关键字 virtual 变为虚继承
//Animal 称为 虚基类
//羊类
class Sheep :virtual public Animal
{};
//驼类
class Tuo :virtual public Animal
{};
//羊驼类
class SheepTuo :public Sheep, public Tuo
{
public:
};
void test01() {
SheepTuo st;
//st.m_Age = 8; //报错 不明确 因为羊驼继承了两份数据
st.Sheep::m_Age = 18;
st.Tuo::m_Age = 28;
//当出现菱形继承时 两个父类拥有相同数据,需要加作用域区分
cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
//利用虚继承后 共用一份数据 可以这样访问
cout << "st.m_Age" << st.m_Age << endl;
//但这份数据我们只需要一份 导致资源浪费
}
int main() {
test01();
system("pause");
return 0;
}
多态是c++面向对象三大特征之一
多态分为两类:
静态多态和动态多态的区别:
基本使用:
动态多态 满足条件
1.有继承关系
2.子类重写父类的虚函数 (speak)
重写:函数返回值类型 函数名 参数列表 完全相同 (virtual可加可不加)
#include
using namespace std;
#include
//多态
//动物类
class Animal
{
public:
//虚函数
virtual void speak() {
cout << "动物说话" << endl;
}
};
//猫类
class Cat :public Animal
{
public:
//重写 virtual可加可不加
void speak() {
cout << "小猫在喵喵" << endl;
}
};
//狗类
class Dog :public Animal
{
public:
void speak() {
cout << "小狗在旺旺" << endl;
}
};
//执行说话的函数
//地址早绑定 在编译阶段确定函数地址
//若想执行让猫说话 那么这个函数地址就不能提前绑定 需要在运行阶段进行绑定 地址晚绑定
//动态多态 满足条件
//1.有继承关系
//2.子类重写父类的虚函数 (speak)| 重写:函数返回值类型 函数名 参数列表 完全相同
//动态多态 使用
//父类的指针/引用 指向子类对象
void doSpeak(Animal &animal) //Animal & animal = cat
{
animal.speak();
}
void test01() {
Cat cat;
doSpeak(cat); //动物在说话
Dog dog;
doSpeak(dog);
}
int main() {
test01();
system("pause");
return 0;
}
深入剖析:
案例描述:
多态优点:
#include
using namespace std;
#include
//案例一 - 计算机类
//普通实现
class Calculator
{
public:
int getResult(string oper) {
if (oper == "+") {
return m_Num1 + m_Num2;
}
else if(oper == "-") {
return m_Num1 - m_Num2;
}
else if (oper == "*") {
return m_Num1 * m_Num2;
}
//如果想扩展新的功能 需要修改源码
//在真实的开发中 提倡 开闭原则
//开闭原则:对扩展进行开发 对修改进行关闭
}
int m_Num1;
int m_Num2;
};
void test01() {
Calculator cal;
cal.m_Num1 = 10;
cal.m_Num2 = 10;
cout << cal.getResult("+") << endl;
cout << cal.getResult("-") << endl;
cout << cal.getResult("*") << endl;
}
//多态实现
//实现计算器抽象类
class AbstractCal
{
public:
virtual int getResult()
{
return 0;
}
int m_Num1;
int m_Num2;
};
//加法计算器类
class AddCal :public AbstractCal
{
int getResult()
{
return m_Num1 + m_Num2;
}
};
//减法计算器类
class SubCal :public AbstractCal
{
int getResult()
{
return m_Num1 - m_Num2;
}
};
//乘法计算器类
class MulCal :public AbstractCal
{
int getResult()
{
return m_Num1 * m_Num2;
}
};
void test02() {
//多态使用条件
//父类的指针或者引用指向子类对象
//加法
AbstractCal* abc = new AddCal;
abc->m_Num1 = 20;
abc->m_Num2 = 10;
cout << abc->getResult() << endl;
//用完记得销毁
delete abc;
//减法
//让指针更改指向
abc = new SubCal;
abc->m_Num1 = 20;
abc->m_Num2 = 10;
cout << abc->getResult() << endl;
delete abc;
}
int main() {
//test01();
test02();
system("pause");
return 0;
}
在多态中 通常父类中虚函数的实现是毫无意义的 主要都是调用子类重写的内容
因此可将 虚函数 改为 纯虚函数
virtual 返回值类型 函数名 (参数列表) = 0
当类中有了纯虚函数 这个类也称抽象类
抽象类特点:
#include
using namespace std;
#include
class Base
{
public:
virtual void func() = 0;
};
class Son :public Base
{
public:
//重写
virtual void func() {
cout << "func函数调用" << endl;
}
};
void test01() {
//Base b; //出错 抽象类无法实例化对象
//new Base;
//Son s; //出错 抽象类的子类必须要重写父类中的纯虚函数 否则也属于抽象类
Son s; //重写后 不报错
Base* base = new Son;
base->func();
}
int main() {
test01();
system("pause");
return 0;
}
案例描述:
利用多态技术实现本案例 提供抽象制作饮品基类 提供子类制作咖啡和茶叶
#include
using namespace std;
#include
class AbstractDrinking {
public:
//烧水
virtual void Boil() = 0;
//冲泡
virtual void Brew() = 0;
//倒杯
virtual void PourInCup() = 0;
//辅料
virtual void PutSomething() = 0;
//规定流程
void MakeDrink() {
Boil();
Brew();
PourInCup();
PutSomething();
}
};
//咖啡
class Coffee :public AbstractDrinking
{
public:
virtual void Boil() {
cout << "煮农夫山泉" << endl;
}
virtual void Brew() {
cout << "冲泡咖啡" << endl;
}
virtual void PourInCup() {
cout << "将咖啡倒入杯中" << endl;
}
virtual void PutSomething() {
cout << "加入牛奶" << endl;
}
};
//茶水
class Tea :public AbstractDrinking
{
public:
virtual void Boil() {
cout << "煮自来水" << endl;
}
virtual void Brew() {
cout << "冲泡茶叶" << endl;
}
virtual void PourInCup() {
cout << "将茶水倒入杯中" << endl;
}
virtual void PutSomething() {
cout << "加入枸杞" << endl;
}
};
//制作函数
void doWork(AbstractDrinking* abs) {
abs->MakeDrink();
delete abs; //堆区数据释放
}
void test01() {
//制作咖啡
doWork(new Coffee);
cout << "--------------------------------" << endl;
//制作茶水
doWork(new Tea);
}
int main() {
test01();
system("pause");
return 0;
}
多态使用时 如果子类中有属性开辟到堆区 那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构 / 纯虚析构
虚析构和纯虚析构 共性:
虚析构和纯虚析构 区别:
虚析构语法:
virtual ~类名(){ }
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){ }
#include
using namespace std;
#include
class Animal
{
public:
Animal() {
cout << "Animal构造函数调用" << endl;
}
//利用虚析构可以解决 父类指针释放子类对象时不干净的问题
/*
virtual ~Animal() {
cout << "Animal析构函数调用" << endl;
}
*/
//改为虚析构后
/*
Animal构造函数调用
Cat构造函数调用
Tom小猫在说话
Cat析构函数调用
Animal析构函数调用
*/
//纯虚析构
//需要声明 也需要实现
//有了纯虚析构 此类也属于抽象类 无法实例化对象
virtual ~Animal() = 0;
//纯虚函数
virtual void speak() = 0;
};
Animal:: ~Animal() {
cout << "Animal纯虚析构函数调用" << endl;
}
/*
Animal构造函数调用
Cat构造函数调用
Tom小猫在说话
Cat析构函数调用
Animal纯虚析构函数调用
*/
class Cat :public Animal
{
public:
Cat(string name) {
cout << "Cat构造函数调用" << endl;
m_Name = new string(name);
}
void speak() {
cout << *m_Name << "小猫在说话" << endl;
}
~Cat() {
if (m_Name != NULL) {
cout << "Cat析构函数调用" << endl;
delete m_Name;
m_Name = NULL;
}
}
string* m_Name;
};
void test01() {
Animal* animal = new Cat("Tom");
animal->speak();
/*
Animal构造函数调用
Cat构造函数调用
Tom小猫在说话
Animal析构函数调用
*/
//父类指针在析构时候 不会调用子类中析构函数 导致子类如果有堆区属性 会导致泄露情况
delete animal;
}
int main() {
test01();
system("pause");
return 0;
}
案例描述:
#include
using namespace std;
#include
class CPU
{
public:
virtual void calculate() = 0;
};
class VideoCard
{
public:
virtual void display() = 0;
};
class Memory
{
public:
virtual void storage() = 0;
};
class Computer
{
public:
//构造函数中传入三个零件指针
Computer(CPU* cpu, VideoCard* vc, Memory* mem) {
m_cpu = cpu;
m_vc = vc;
m_mem = mem;
}
//提供一个工作的函数
void work() {
m_cpu->calculate();
m_vc->display();
m_mem->storage();
}
//提供析构函数 释放3个电脑零件
~Computer() {
if (m_cpu != NULL) {
delete m_cpu;
m_cpu = NULL;
}
if (m_vc != NULL) {
delete m_vc;
m_vc = NULL;
}
if (m_mem != NULL) {
delete m_mem;
m_mem = NULL;
}
}
private:
CPU* m_cpu;
VideoCard* m_vc;
Memory* m_mem;
};
//具体厂商 Inter
class InterCPU :public CPU
{
virtual void calculate() {
cout << "Inter的CPU开始计算了!" << endl;
}
};
class InterVideoCard :public VideoCard
{
virtual void display() {
cout << "Inter的显卡开始显示了!" << endl;
}
};
class InterMemory :public Memory
{
virtual void storage() {
cout << "Inter的内存条开始存储了!" << endl;
}
};
//Lenovo联想厂商
class LenovoCPU :public CPU
{
virtual void calculate() {
cout << "Lenovo的CPU开始计算了!" << endl;
}
};
class LenovoVideoCard :public VideoCard
{
virtual void display() {
cout << "Lenovo的显卡开始显示了!" << endl;
}
};
class LenovoMemory :public Memory
{
virtual void storage() {
cout << "Lenovo的内存条开始存储了!" << endl;
}
};
void test01() {
//第一台电脑零件
CPU* interCpu = new InterCPU;
VideoCard* interCard = new InterVideoCard;
Memory* interMem = new InterMemory;
//创建第一台电脑
Computer* computer1 = new Computer(interCpu, interCard, interMem);
computer1->work();
delete computer1;
cout << "-----------------------------------------" << endl;
//组装第二台电脑
Computer* computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);
computer2->work();
delete computer2;
cout << "-----------------------------------------" << endl;
//组装第三台电脑
Computer* computer3 = new Computer(new InterCPU, new LenovoVideoCard, new LenovoMemory);
computer3->work();
delete computer3;
}
int main() {
test01();
system("pause");
return 0;
}
程序运行时产生的数据都属于临时数据 程序一旦运行结束都会被释放
通过文件可以将数据持久化
c++中对文件操作需要包含头文件
文件类型分为两种:
操作文件的三大类:
步骤:
文件打开方式
注意:
#include
using namespace std;
#include //1.头文件包含
void test01() {
//2.创建流对象
ofstream ofs;
//3.指定打开方式
ofs.open("test.txt", ios::out);
//4.写内容
ofs << "姓名:张三 " << endl;
ofs << "姓名:李四 " << endl;
ofs << "姓名:王五 " << endl;
//5.关闭文件
ofs.close();
}
int main() {
test01();
system("pause");
return 0;
}
总结:
步骤:
#include
using namespace std;
#include
#include //1.头文件包含
void test01() {
//2.创建流对象
ifstream ifs;
//3.打开文件并且判断是否打开成功
ifs.open("test.txt", ios::in);
if (!ifs.is_open()) {
cout << "打开失败" << endl;
return;
}
//4.读数据
//第一种
/*
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) //EOF end of file
{
cout << c;
}
//5.关闭文件
ifs.close();
}
int main() {
test01();
system("pause");
return 0;
}
以二进制的方式对文件进行读写操作
打开方式要指定为ios::binary
二进制方式写文件主要利用流对象调用成员函数write
函数原型:ostream& write(const char * buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间 len是读写的字节数
#include
using namespace std;
#include
#include
//二进制文件 写文件
class Person
{
public:
char m_Name[64];
int m_Age;
};
void test01() {
//1.包含头文件
//2.创建流对象
ofstream ofs("Person.txt", ios::out | ios::binary);
//3.打开文件
//ofs.open("Person.txt",ios::out | ios::binary);
//可以和上一步 创建流对象 合并
//4.写文件
Person p = { "张三",18 };
ofs.write((const char *) & p,sizeof(Person));
//5.关闭文件
ofs.close();
}
int main() {
test01();
system("pause");
return 0;
}
二进制方式读文件主要利用流对象调用成员函数read
函数原型: istream& read(char *buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间 len是读写的字节数