文章目录
- 第四章:
- 4.类和对象
- 4.1 封装
- 4.1.1 封装的意义
- 4.1.2 struct与class的区别
- 4.2 对象的初始化和清理
- 4.2.1 构造函数和析构函数
- 4.2.2 构造函数的分类及调用
- 4.2.3 拷贝构造函数调用时机
- 4.2.4 构造函数调用规则
- 4.2.5 深拷贝与浅拷贝
- 4.2.6 初始化列表
- 4.2.7 类对象作为类成员
- 4.2.8 静态成员
- 4.3 C++对象模型和this指针
- 4..3.1 成员变量和成员函数分开存储
- 4.3.2 this指针
- 4.3.3 空指针访问成员函数
- 4.3.4 const修饰成员函数
- 4.4 友元
- 4.4.1 全局函数做友元
- 4.4.2 类做友元
- 4.4.3 成员函数做友元
- 4.5 运算符重载
- 4.5.1 加号运算符重载
- 4.5.2 左移运算符重载
- 4.5.3 递增运算符重载
- 4.5.4 赋值运算符重载
- 4.5.5 关系运算符重载
- 4.5.6 函数调用运算符重载
- 4.6 继承
- 4.6.1 继承基本语法
- 4.6.2 继承方式
- 4.6.3 继承中的对象模型
- 4.6.4 继承中构造和析构顺序
- 4.6.5 继承同名成员处理方式
- 4.6.6 继承同名静态成员处理方式
- 4.6.7 多继承语法
- 4.6.8 菱形继承
- 4.7 多态
- 4.7.1 多态基本概念
- 4.7.2 纯虚函数和抽象类
- 4.7.3 虚析构和纯虚析构
- 4.7.4 多态案例
- 案例一:制作计算器类
- 案例二:制作冷饮
- 案例三:组装电脑
第四章:
4.类和对象
C++面对对象的三大特征:封装、继承、多态
4.1 封装
4.1.1 封装的意义
-
将属性和行为作为一个整体,常用来表现生活中的事物
-
将属性和行为加以权限以便进行控制
语法结构:class 类名 { 访问权限: 属性 / 行为 };
#include <iostream>
using namespace std;
const int PI = 3.14;
class Circle
{
//访问权限
//public - 公共权限
public:
//属性
//半径
int m_r;
//行为
//计算圆的面积
double calculateCircleArea()
{
return PI * (m_r * m_r);
}
};
int main()
{
//创建一个具体的圆(对象)
Circle c1;
//对圆(对象)的属性进行赋值操作
c1.m_r = 3;
cout << "半径为" << c1.m_r << "的面积为" << c1.calculateCircleArea() << endl;
system("pause");
return 0;
}
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
void getID(int id)
{
m_id = id;
}
void getName(string name)
{
m_name = name;
}
void getAge(int age)
{
m_age = age;
}
void showStudent()
{
cout << m_name << "学号是" << m_id << "年龄是" << m_age << endl;
}
public:
int m_id;
string m_name;
int m_age;
};
int main()
{
Student s1;
s1.getID(123456);
s1.getName("小明");
s1.getAge(18);
s1.showStudent();
system("pause");
return 0;
}
三种访问权限:
-
public 公共权限
-
protected 保护权限
-
private 私有权限
#include <iostream>
using namespace std;
// public - 类内可访问,类外可访问
// protected - 类内可访问,类外不可访问
// private - 类内可访问,类外不可访问
class Person
{
public:
string m_Name;
protected:
string m_Phone;
private:
string m_Password;
public:
void func()
{
m_Name = "小红";
m_Phone = "HW";
m_Password = "ABC123";
}
};
int main()
{
Person p1;
p1.m_Name = "小明";
p1.m_Phone = "HW"; //报错,protected类外不可访问
p1.m_Password = "abc123"; //报错,private类外不可访问
system("pause");
return 0;
}
4.1.2 struct与class的区别
默认访问权限不同:
-
struct默认权限为公共
-
class 默认权限为私有
#include <iostream>
#include <string>
using namespace std;
struct Person1
{
string m_Name;
};
class Person2
{
string m_Name;
};
int main()
{
Person1 p1;
p1.m_Name = "小明";
Person2 p2;
p2.m_Name = "小红"; //报错
system("pause");
return 0;
}
4.2 对象的初始化和清理
4.2.1 构造函数和析构函数
对象的初始化和清理是两个重要的安全问题:
-
一个对象或变量没有初始状态,对于其使用后的结果是未知的。
-
使用完一个对象或变量,没及时清理会造成一定的安全问题。
在C++中使用构造函数和析构函数来解决以上问题,如果我们不提供构造和析构函数,编译器会提供构造函数和析构函数(空实现)。
-
构造函数:作用于创建对象时对对象的成员属性进行赋值,构造函数有编译器自动调用,无需手动调用。
-
析构函数:作用于在对象销毁前系统自动调用,进行清理工作。
构造函数语法结构:类名(){}
-
无返回值,无需写void
-
函数名和类型相同
-
可以有参数,因此可发生重载
-
程序在调用对象时会自动调用,无序手动调用,指挥调用一次
析构函数语法结构:~类名(){}
-
无返回值,无需写void
-
函数名于类名相同,在名称前加上符号~
-
不可有参数,由此不可发生重载
-
程序在对象销毁前会自动调用,无序手动调用,只会调用一次。
#include <iostream>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student的构造函数调用" << endl;
}
~Student()
{
cout << "Student的析构函数调用" << endl;
}
};
void test()
{
Student s;
}
int main()
{
test();
system("pause");
return 0;
}
4.2.2 构造函数的分类及调用
两种分类方式:
-
参数分为:有参构造和无参构造
-
类型分为:普通构造和拷贝构造
三种调用方式:
-
括号法
-
显示法
-
隐式转换法
#include <iostream>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student的默认构造函数调用" << endl;
}
Student(int a)
{
age = a;
cout << "Student的有参构造函数调用" << endl;
}
Student(const Student& s)
{
age = s.age;
cout << "Student的拷贝构造函数调用" << endl;
}
~Student()
{
cout << "Student的析构函数调用" << endl;
}
int age;
};
void test()
{
//1.括号法
//Student s1(); //调用默认构造函数时,不要加(),编译器会认为是一个函数的声明
Student s1; //默认构造函数调用
Student s2(18); //有参构造函数调用
Student s3(s2); //拷贝构造函数调用
cout << "s2的年龄是" << s2.age << endl;
cout << "s3的年龄是" << s3.age << endl;
//2.显示法
Student s4;
Student s5 = Student(19);
Student s6 = Student(s5);
//Student(20); //匿名对象,当前行执行结束后,系统自动回收掉。
//Student(s6); //不要用拷贝构造函数,初始化匿名对象,编译器会认为Student(s5)= Student s5;
//
//3.隐式转换法
Student s7 = 17; //相当于Student s7 = Student(17)
Student s8 = s7;
}
int main()
{
test();
system("pause");
return 0;
}
4.2.3 拷贝构造函数调用时机
三种情况:
-
使用一个已经创建完毕的对象来初始化一个新的对象
-
值传递的方式给函数参数传值
-
以值方式返回局部对象
#include <iostream>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student的默认构造函数调用" << endl;
}
Student(int age)
{
cout << "Student的有参构造函数调用" << endl;
m_age = age;
}
Student(const Student& s)
{
cout << "Student的拷贝构造函数调用" << endl;
m_age = s.m_age;
}
~Student()
{
cout << "Student的析构构造函数调用" << endl;
}
int m_age;
};
//使用一个已经创建完毕的对象来初始化一个新的对象
void test01()
{
Student s1(18);
Student s2(s1);
cout << "s2的年龄是" << s2.m_age << endl;
}
void Work1( Student s)
{
}
//值传递的方式给函数参数传值
void test02()
{
Student s3;
Work1(s3);
}
Student work2()
{
Student s5;
cout << &s5 << endl;
return s5;
}
//以值方式返回局部对象
void test03()
{
Student s4 = work2();
cout << &s4 << endl;
}
int main()
{
test01();
test02();
test03();
system("pause");
return 0;
}
4.2.4 构造函数调用规则
默认情况下,C++编译器中至少会给一个类添加三个函数:
-
默认构造函数(无参,函数体为空)
-
默认拷贝构造函数,对属性进行值拷贝
-
默认析构函数(无参,函数体为空)
调用规则:
-
如果用户定义了有参构造函数,C++将不会提供默认无参构造函数,但会提供默认拷贝构造函数。
-
如果用户定义了拷贝构造函数,C++将不会提供其他的构造函数。
//如果用户定义了有参构造函数,C++将不会提供默认无参构造函数,但会提供默认拷贝构造函数。
#include <iostream>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student的默认构造函数调用" << endl;
}
Student(int age)
{
cout << "Student的有参构造函数调用" << endl;
m_age = age;
}
/*Student(const Student& s)
{
cout << "Student的拷贝构造函数调用" << endl;
m_age = s.m_age;
}*/
~Student()
{
cout << "Student的析构函数调用" << endl;
}
int m_age;
};
void test01()
{
Student s1;
s1.m_age = 18;
Student s2(s1);
cout << "s2的年龄是:" << s2.m_age << endl;
}
//void test02()
//{
// Student s3(20);
// Student s4(s3);
// cout << "s4的年龄是" << s4.m_age << endl;
//}
int main()
{
test01();
//test02();
system("pause");
return 0;
}
#include <iostream>
using namespace std;
class Student
{
public:
/*Student()
{
cout << "Student的默认构造函数调用" << endl;
}*/
Student(int age)
{
cout << "Student的有参构造函数调用" << endl;
m_age = age;
}
Student(const Student& s)
{
cout << "Student的拷贝构造函数调用" << endl;
m_age = s.m_age;
}
~Student()
{
cout << "Student的析构函数调用" << endl;
}
int m_age;
};
//void test01()
//{
// Student s1;
// s1.m_age = 18;
// Student s2(s1);
// cout << "s2的年龄是:" << s2.m_age << endl;
//}
void test02()
{
Student s3(20);
Student s4(s3);
cout << "s4的年龄是" << s4.m_age << endl;
}
int main()
{
/*test01();*/
test02();
system("pause");
return 0;
}
4.2.5 深拷贝与浅拷贝
浅拷贝:赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作
#include <iostream>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student的默认构造函数调用" << endl;
}
Student(int age, int weight)
{
m_age = age;
m_weight = new int(weight);
cout << "Student的有参构造函数调用" << endl;
}
Student(const Student& s)
{
cout << "Student的拷贝构造函数调用" << endl;
m_age = s.m_age;
m_weight = new int(*s.m_weight);
}
~Student()
{
if (m_weight != NULL)
{
delete m_weight;
m_weight = NULL;
}
cout << "Student的析构函数调用" << endl;
}
int m_age;
int* m_weight;
};
void test01()
{
Student s1(18, 120);
cout << "s1的年龄是" << s1.m_age << ",体重是:" << *s1.m_weight << endl;
Student s2(s1);
cout << "s2的年龄是" << s2.m_age << ",体重是:" << *s2.m_weight << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
4.2.6 初始化列表
作用:初始化属性
语法结构:构造函数():属性1(值1), 属性2(值2)…{}
#include <iostream>
using namespace std;
class Student
{
public:
Student():m_age(18),m_height(180)
{
}
Student(int age, int height) :m_age(age), m_height(height)
{
}
int m_age;
int m_height;
};
void test01()
{
Student s1;
cout << "s1的年龄是" << s1.m_age << endl;
cout << "s1的身高是" << s1.m_height << endl;
Student s2(20,175);
cout << "s2的年龄是" << s2.m_age << endl;
cout << "s2的身高是" << s2.m_height << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
4.2.7 类对象作为类成员
C++的类中成员可以是另一个类的对象,称该成员为对象成员。
#include <iostream>
#include <string>
using namespace std;
class Phone
{
public:
Phone(string pName)
{
m_PName = pName;
cout << "Phone的构造函数调用" << endl;
}
~Phone()
{
cout << "Phone的析构函数调用" << endl;
}
string m_PName;
};
class Student
{
public:
Student(string name, string pName):m_Name(name), m_Phone(pName)
{
/* m_Name = name;
m_Phone = pName;*/
cout << "Student的构造函数调用" << endl;
}
~Student()
{
cout << "Student的析构函数调用" << endl;
}
string m_Name;
Phone m_Phone;
};
void test01()
{
Student s1("小明", "HW");
cout << s1.m_Name << "使用" << s1.m_Phone.m_PName << "手机" << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
总结:当其他类对象作为本类成员时,构造时先构造类对象,再构造自身,析构的顺序与构造相反。
4.2.8 静态成员
在成员变量和成员函数前加上关键字static,称为静态成员。
分类:
-
静态成员变量
所有对象共享同一份数据 在编译阶段时分配内存 类内声明,类外初始化
-
静态成员函数
所有对象共享同个函数
静态成员函数只能访问静态成员变量
静态成员变量:
#include <iostream>
using namespace std;
class Student
{
public:
static int m_A;
private:
static int m_B;
};
int Student::m_A = 10;
int Student::m_B = 20;
void test01()
{
//静态成员变量两种访问方式
//通过对象
Student s1;
s1.m_A = 100;
cout << "s1的m_A值为:" << s1.m_A << endl;
Student s2;
s2.m_A = 200;
cout << "s1的m_A值为:" << s1.m_A << endl; //共享同一份数据
cout << "s2的m_A值为:" << s2.m_A << endl;
//通过类名
cout << "s1的m_A值为:" << Student::m_A << endl;
cout << "s2的m_A值为:" << Student::m_A << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
静态成员函数:
#include <iostream>
using namespace std;
class Student
{
public:
static void func()
{
m_A = 10; //静态成员函数可访问静态成员变量
//m_B = 20; //报错,静态成员函数不可访问非静态成员变量
cout << "statc void func函数的调用" << endl;
}
private:
static void func2()
{
m_A = 10;
//m_B = 20;
cout << "statc void func2函数的调用" << endl;
}
public:
static int m_A;
int m_B;
};
int Student::m_A = 10;
//int Student::m_B = 20; //报错,非静态成员变量不可在类外定义
void test01()
{
//通过对象访问
Student s1;
s1.func();
//通过类名访问
Student::func();
//Student::func2(); //报错,类外访问不到私有静态成员函数
}
int main()
{
test01();
system("pause");
return 0;
}
4.3 C++对象模型和this指针
4…3.1 成员变量和成员函数分开存储
在C++中,只有非静态成员变量才属于类的对象上。
#include <iostream>
using namespace std;
class Student
{
public:
int m_A; //非静态成员变量 属于类的对象上
static int m_B; //静态成员变量 不属于类的对象上
void func(){} //非静态成员函数 属于类的对象上
void func2(){} //静态成员变量 不属于类的对象上
};
void test01()
{
Student s1;
cout << sizeof(s1) << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
补充:空对象占用内存空间为1,C++编译器会给每个空对象也分配一个字节空间,以便区分对象占用内存的位置。
4.3.2 this指针
定义:this指针指向被调用的成员函数所属的对象,隐含每一个非静态成员函数内的一种指针。
作用:
-
当形参和成员变量同名时,可用this指针来进行区分
-
在类的非静态成员函数中返回对象本身,可用return *this
#include <iostream>
using namespace std;
class Student
{
public:
Student(int age)
{
//当形参和成员变量同名时,可用this指针来进行区分
this->age = age;
}
Student& stuAddAge(Student &s)
{
this->age += s.age;
//在类的非静态成员函数中返回对象本身,可用return *this
return *this;
}
int age;
};
void test01()
{
Student s1(18);
cout << "s1的年龄是" << s1.age << endl; //s1的年龄是18
Student s2(20);
s2.stuAddAge(s1);
cout << "s2的年龄是" << s2.age << endl; //s2的年龄是38
}
int main()
{
test01();
system("pause");
return 0;
}
4.3.3 空指针访问成员函数
#include <iostream>
using namespace std;
class Student
{
public:
void showClassName()
{
cout << "This is Student" << endl;
}
void showClassAge()
{
if (this == NULL)
return;
//如果没有if判断的话会报错,因为传入的指针为NULL
cout << "m_age = " << this->m_age << endl;
}
int m_age;
};
void test01()
{
Student* s = NULL;
s->showClassName();
s->showClassAge();
}
int main()
{
test01();
system("pause");
return 0;
}
补充:空指针是可以调用成员函数的,但要注意是否用到this指针,用到的话需要加以判断来保证代码的健壮性。
4.3.4 const修饰成员函数
常函数:
-
成员函数后加上const后,称该函数为常函数
-
常函数内不可修改成员的属性
-
成员属性声明时加上关键字mutable后,在常函数依旧可修改
常对象:
-
声明对象前加上const后,称该对象为常对象
-
常对象只能调用常函数
#include <iostream>
using namespace std;
class Student
{
public:
//this指针本质上是一个指针常量,指针的指向是不可修改的
//在成员函数后加上const,修饰的是this指向,让指针指向的值也不可被修改
//const Student * const this
void modifyStudent() const
{
//this->m_A = 100; //报错
this->m_B = 200;
//this = NULL; //this指针不能修改指针的指向
}
void func()
{
cout << "This is func" << endl;
}
int m_A;
mutable int m_B; //特殊变量,即使在常函数中,也可修改
};
void test01()
{
Student s;
s.modifyStudent();
}
//常对象
void test02()
{
const Student s2; //常对象
//s2.m_A = 100; //报错
s2.m_B = 200;
s2.modifyStudent();
//s2.func(); //报错,常对象只能调用常函数,不能调用普通成员函数,普通成员函数可以修改属性
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
4.4 友元
作用:让一个函数或类访问另一个类中私有成员。
关键字:friend
三种实现:
-
全局函数做友元
-
类做友元
-
成员函数做友元
4.4.1 全局函数做友元
#include <iostream>
using namespace std;
class House
{
friend void Visit(House* house);
public:
House()
{
m_LivingRoom = "客厅";
m_BedRoom = "卧室";
}
public:
string m_LivingRoom;
private:
string m_BedRoom;
};
void Visit(House* house)
{
cout << "正在参观" << house->m_LivingRoom << endl;
cout << "正在参观" << house->m_BedRoom << endl;
}
void test01()
{
House h;
Visit(&h);
}
int main()
{
test01();
system("pause");
return 0;
}
4.4.2 类做友元
#include <iostream>
#include <string>
using namespace std;
class House;
class goodfriend
{
public:
goodfriend();
void visit();
private:
House* house;
};
class House
{
friend class goodfriend;
public:
House();
public:
string m_LivingRoom;
private:
string m_BedRoom;
};
House::House()
{
this->m_LivingRoom = "客厅";
this->m_BedRoom = "卧室";
}
goodfriend::goodfriend()
{
house = new House;
}
void goodfriend::visit()
{
cout << "正在参观" << house->m_LivingRoom << endl;
cout << "正在参观" << house->m_BedRoom << endl;
}
void test01()
{
goodfriend gf;
gf.visit();
}
int main()
{
test01();
system("pause");
return 0;
}
4.4.3 成员函数做友元
#include <iostream>
#include <string>
using namespace std;
class House;
class goodfriend
{
public:
goodfriend();
void visit();
void visit2();
private:
House* house;
};
class House
{
friend void goodfriend::visit();
public:
House();
public:
string m_LivingRoom;
private:
string m_BedRoom;
};
House::House()
{
this->m_LivingRoom = "客厅";
this->m_BedRoom = "卧室";
}
goodfriend::goodfriend()
{
house = new House;
}
void goodfriend::visit()
{
cout << "正在参观" << house->m_LivingRoom << endl;
cout << "正在参观" << house->m_BedRoom << endl;
}
void goodfriend::visit2()
{
cout << "正在参观" << house->m_LivingRoom << endl;
//cout << "正在参观" << house->m_BedRoom << endl;
}
void test01()
{
goodfriend gf;
gf.visit();
gf.visit2();
}
int main()
{
test01();
system("pause");
return 0;
}
4.5 运算符重载
作用:对已有的运算符进行重新定义,赋予另一种功能,以适应不同的数据类型。
4.5.1 加号运算符重载
作用:实现两个自定义数据类型相加的运算
#include <iostream>
using namespace std;
class Student
{
public:
//成员函数加号运算符重载
/*Student operator+(Student& s)
{
Student temp;
temp.m_A = this->m_A + s.m_A;
temp.m_B = this->m_B + s.m_B;
return temp;
}*/
int m_A;
int m_B;
};
//全局函数加号运算符重载
Student operator+(Student& s1, Student& s2)
{
Student temp;
temp.m_A = s1.m_A + s2.m_A;
temp.m_B = s1.m_B + s2.m_B;
return temp;
}
//函数重载
Student operator+(Student& s, int val)
{
Student temp;
temp.m_A = s.m_A + val;
temp.m_B = s.m_B + val;
return temp;
}
void test01()
{
Student s1;
s1.m_A = 10;
s1.m_B = 20;
Student s2;
s2.m_A = 10;
s2.m_B = 20;
Student s3 = s1 + s2;
Student s4 = s1 + 10;
//成员函数本质调用
//Student s3 = s1.operator+(s2);
//全局函数本质调用
//Student s3 = operator+(s1, s3);
cout << "s3 - m_A = " << s3.m_A << endl;
cout << "s3 - m_B = " << s3.m_B << endl;
cout << "s4 - m_A = " << s4.m_A << endl;
cout << "s4 - m_B = " << s4.m_B << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
4.5.2 左移运算符重载
作用:可输出自定义数据类型。
#include <iostream>
using namespace std;
class Student
{
friend ostream& operator<<(ostream& cout, Student& s);
public:
Student(int a, int b)
{
m_A = a;
m_B = b;
}
private:
int m_A;
int m_B;
};
//使用成员函数重载左移运算符 s1.operator<<(cout) s1 << cout,但无法实现,因为cout在左侧
//只能使用全局函数重载左移运算符
//全局函数重载调用本质 operator<< (cout , p) cout << p
ostream& operator<<(ostream &cout, Student &s)
{
cout << "m_A = " << s.m_A << " " << "m_B = " << s.m_B << endl;
return cout;
}
void test01()
{
Student s1(10, 20);
cout << s1 << endl;
cout << "hello C++" << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
4.5.3 递增运算符重载
作用:实现自己的整型数据。
#include <iostream>
using namespace std;
class MyIntData
{
friend ostream& operator<<(ostream& cout, MyIntData myInt);
public:
MyIntData()
{
m_Num = 0;
}
//前置++
MyIntData& operator++()
{
m_Num++;
return *this; //将自身返回
}
//后置++
MyIntData operator++(int)
{
MyIntData temp = *this; //先记录当前结果
m_Num++; //递增
return temp; //将记录结果返回
}
private:
int m_Num;
};
ostream& operator<<(ostream& cout, MyIntData myInt)
{
cout << myInt.m_Num;
return cout;
}
void test01()
{
MyIntData myInt;
cout << ++myInt << endl;
cout << myInt << endl;
}
void test02()
{
MyIntData myInt2;
cout << myInt2++ << endl;
cout << myInt2 << endl;
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
4.5.4 赋值运算符重载
C++编译器至少给一个类添加了4个函数:
-
默认构造函数(无参,函数体为空)
-
默认析构函数(无参,函数体为空)
-
默认拷贝构造函数,对属性进行值拷贝
-
赋值运算符 operator=,对属性进行值拷贝
类中有属性指向堆区,赋值操作时也会出现深浅拷贝问题。
#include <iostream>
using namespace std;
class Student
{
public:
Student(int age)
{
m_Age = new int(age);
}
~Student()
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
}
Student& operator=(Student& s)
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
m_Age = new int(*s.m_Age);
return *this;
}
int *m_Age;
};
void test01()
{
Student s1(18);
Student s2(20);
Student s3(19);
s1 = s2 = s3;
cout << "s1的年龄是:" << *s1.m_Age << endl;
cout << "s2的年龄是:" << *s2.m_Age << endl;
cout << "s3的年龄是:" << *s2.m_Age << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
4.5.5 关系运算符重载
作用:可让两个自定义类型对象进行比较操作。
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student(string name, int age)
{
m_Name = name;
m_Age = age;
}
bool operator==(Student& s)
{
if (this->m_Age == s.m_Age && this->m_Name == s.m_Name)
return true;
return false;
}
bool operator!=(Student& s)
{
if (this->m_Age == s.m_Age && this->m_Name == s.m_Name)
return false;
return true;
}
string m_Name;
int m_Age;
};
void test01()
{
Student s1("小明", 18);
Student s2("小红", 18);
if (s1 == s2)
{
cout << "s1 = s2" << endl;
}
else
{
cout << "s1 != s2" << endl;
}
if (s1 != s2)
{
cout << "s1 != s2" << endl;
}
else
{
cout << "s1 = s2" << endl;
}
}
int main()
{
test01();
system("pause");
return 0;
}
4.5.6 函数调用运算符重载
-
函数调用运算符()也可重载
-
重载后使用的方式极其像函数的调用方式,因此称为仿函数
-
仿函数无固定写法,比较灵活
#include <iostream>
using namespace std;
class Printf
{
public:
void operator()(string test)
{
cout << test << endl;
}
};
void Printf02(string test)
{
cout << test << endl;
}
class numAdd
{
public:
int operator()(int value1, int value2)
{
return value1 + value2;
}
};
void test01()
{
Printf p;
p("Hello C++"); //仿函数
Printf02("Hello C++");
}
void test02()
{
numAdd a;
int result = a(10, 20);
cout << "result = " << result << endl;
cout << " numAdd()(20, 20) = " << numAdd()(20, 20) << endl; //匿名对象调用
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
4.6 继承
继承是面向对象三大特性之一。
类与类存在着特殊的关系:
下级成员不仅有上一级的共性,还会有自己的特性,利用继承技术,可减少重复代码。
4.6.1 继承基本语法
语法结构:class 子类 : 继承方式 父类
#include <iostream>
using namespace std;
class BasePage
{
public:
void top()
{
cout << "欢迎来到abc线上购物中心" << endl;
}
void left()
{
cout << "Shoes、Water、Paper、Clothes...(公共分类列表)" << endl;
}
void bottom()
{
cout << "服务中心、购物指导、联系我们...(公共底部)" << endl;
}
};
class Shoes :public BasePage
{
public:
void conter()
{
cout << "You can buy shoes" << endl;
}
};
class Water :public BasePage
{
public:
void conter()
{
cout << "You can buy water" << endl;
}
};
class Paper :public BasePage
{
public:
void conter()
{
cout << "You can buy paper" << endl;
}
};
class Clothes :public BasePage
{
public:
void conter()
{
cout << "You can buy clothes" << endl;
}
};
void test01()
{
cout << "鞋子购买页面如下:" << endl;
Shoes sh;
sh.top();
sh.bottom();
sh.left();
sh.conter();
cout << "--------------------" << endl;
cout << "矿泉水购买页面如下:" << endl;
Water wt;
wt.top();
wt.bottom();
wt.left();
wt.conter();
cout << "--------------------" << endl;
cout << "纸巾购买页面如下:" << endl;
Paper pr;
pr.top();
pr.bottom();
pr.left();
pr.conter();
cout << "--------------------" << endl;
cout << "衣服购买页面如下:" << endl;
Clothes cl;
cl.top();
cl.bottom();
cl.left();
cl.conter();
}
int main()
{
test01();
return 0;
}
补充:
-
子类也称派生类
-
父类也称基类
派生类成员含两大部分:
-
从积累继承过来的
-
自己增加的成员
基类继承来的成员体现其共性,新增成员体现其个性。
4.6.2 继承方式
继承语法结构:class 子类 : 继承方式 父类
三种继承方式:
-
公共继承
-
保护继承
-
私有继承
#include <iostream>
using namespace std;
class Father
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son1 :public Father
{
public:
void func()
{
m_A = 10; //父类中的公共权限成员,到子类依然是公共权限
m_B = 20; //父类中的保护权限成员,到子类依然是保护权限
//m_C = 30; //报错,父类中的私有权限成员,子类没权限访问
}
};
class Son2 :protected Father
{
public:
void func()
{
m_A = 10; //父类中的公共权限成员,到子类变保护权限
m_B = 20; //父类中的保护权限成员,到子类依然是保护权限
//m_C = 30; //报错,父类中的私有权限成员,子类没权限访问
}
};
class Son3 :private Father
{
public:
void func()
{
m_A = 10; //父类中的公共权限成员,到子类变私有权限
m_B = 20; //父类中的保护权限成员,到子类变私有权限
//m_C = 30; 报错,父类中的私有权限成员,子类没权限访问
}
};
class GrandSon :public Son3
{
public:
void func()
{
//m_A = 10; //报错,m_A变为私有权限,访问不到
//m_B = 20; //报错,m_B变为私有权限,访问不到
}
};
void test01()
{
Son1 s1;
s1.m_A = 10;
//s1.m_B = 20; //报错,m_B是保护权限,类外访问不到
Son2 s2;
//s2.m_A = 10; //报错,m_A是保护权限,类外访问不到
//s2.m_B = 20; //报错,m_B是保护权限,类外访问不到
Son3 s3;
//s3.m_A = 10; //报错,m_A是私有权限,类外访问不到
//s3.m_B = 20; //报错,m_B是私有权限,类外访问不到
}
int main()
{
test01();
system("pause");
return 0;
}#include <iostream>
using namespace std;
class Father
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son1 :public Father
{
public:
void func()
{
m_A = 10; //父类中的公共权限成员,到子类依然是公共权限
m_B = 20; //父类中的保护权限成员,到子类依然是保护权限
//m_C = 30; //报错,父类中的私有权限成员,子类没权限访问
}
};
class Son2 :protected Father
{
public:
void func()
{
m_A = 10; //父类中的公共权限成员,到子类变保护权限
m_B = 20; //父类中的保护权限成员,到子类依然是保护权限
//m_C = 30; //报错,父类中的私有权限成员,子类没权限访问
}
};
class Son3 :private Father
{
public:
void func()
{
m_A = 10; //父类中的公共权限成员,到子类变私有权限
m_B = 20; //父类中的保护权限成员,到子类变私有权限
//m_C = 30; 报错,父类中的私有权限成员,子类没权限访问
}
};
class GrandSon :public Son3
{
public:
void func()
{
//m_A = 10; //报错,m_A变为私有权限,访问不到
//m_B = 20; //报错,m_B变为私有权限,访问不到
}
};
void test01()
{
Son1 s1;
s1.m_A = 10;
//s1.m_B = 20; //报错,m_B是保护权限,类外访问不到
Son2 s2;
//s2.m_A = 10; //报错,m_A是保护权限,类外访问不到
//s2.m_B = 20; //报错,m_B是保护权限,类外访问不到
Son3 s3;
//s3.m_A = 10; //报错,m_A是私有权限,类外访问不到
//s3.m_B = 20; //报错,m_B是私有权限,类外访问不到
}
int main()
{
test01();
system("pause");
return 0;
}
4.6.3 继承中的对象模型
从父类继承过来的成员,哪些是属于子类对象中呢?
#include <iostream>
using namespace std;
class Father
{
public:
int a;
protected:
int b;
private:
int c;
};
class Son : public Father
{
public:
int d;
};
void test01()
{
//父类中的所有非静态成员属性都被被子类所继承下去
//父类中的私有成员属性也会被继承下去,只是被编译器隐藏了,因此访问不到
cout << "sizeof(Son)的结果为" << sizeof(Son) << endl; //16
}
int main()
{
test01();
system("pause");
return 0;
}
4.6.4 继承中构造和析构顺序
子类在继承父类后,创建子类对象,也会调用父类的构造函数。
#include <iostream>
using namespace std;
class Father
{
public:
Father()
{
cout << "Father的构造函数调用" << endl;
}
~Father()
{
cout << "Father的析构函数调用" << endl;
}
};
class Son : public Father
{
public:
Son()
{
cout << "Son的构造函数调用" << endl;
}
~Son()
{
cout << "Son的析构函数调用" << endl;
}
};
void test01()
{
Son s1;
}
int main()
{
test01();
system("pause");
return 0;
}
总结:先构造父类,再构造子类,析构的顺序跟构造相反。
4.6.5 继承同名成员处理方式
子类与父类中有同名的成员,怎样通过子类对象,访问到子类或父类中同名的数据呢?
-
访问子类同名成员 直接访问即可
-
访问父类同名成员 加作用域即可
#include <iostream>
using namespace std;
class Father
{
public:
Father()
{
m_A = 10;
}
void func()
{
cout << "Father - func调用" << endl;
}
void func(int )
{
cout << "Father - func(int)调用" << endl;
}
int m_A;
};
class Son :public Father
{
public:
Son()
{
m_A = 20;
}
void func()
{
cout << "Son - func调用" << endl;
}
int m_A;
};
void test01()
{
Son s1;
cout << "s1 m_A = " << s1.m_A << endl;
cout << "Father m_A = " << s1.Father::m_A << endl;
Son s2;
s2.func();
s2.Father::func();
//s2.func(30) //报错
//子类中如果出现与父类同名的成员函数,子类会将父类中的所有同名成员函数隐藏
}
int main()
{
test01();
system("pause");
return 0;
}
总结:子类对象可直接访问子类中同名成员,子类对象加上作用域可访问到父类同名成员,当子类与父类有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可访问到父类中同名函数。
4.6.6 继承同名静态成员处理方式
继承中同名的静态成员怎样在子类对象上进行访问呢?
静态成员与非静态成员出现同名的情况,处理方式一样
-
访问子类同名成员 直接访问即可
-
访问父类同名成员 加作用域即可
#include <iostream>
using namespace std;
class Base
{
public:
static int m_A;
static void func()
{
cout << "Base - static void func调用" << endl;
}
static void func(int)
{
cout << "Son - static void func(int)调用" << endl;
}
};
int Base::m_A = 10; //类外初始化
class Son :public Base
{
public:
static int m_A;
static void func()
{
cout << "Son - static void func调用" << endl;
}
};
int Son::m_A = 20;
//同名静态成员属性
void test01()
{
//通过对象访问
Son s1;
cout << "s1 m_A = " << s1.m_A << endl;
cout << "Base m_A = " << s1.Base::m_A << endl;
//通过类名访问
cout << "s1 m_A = " << Son::m_A << endl;
cout << "Base m_A = " << Son::Base::m_A << endl;
}
//同名静态成员函数
void test02()
{
//通过对象访问
Son s2;
s2.func();
s2.Base::func();
//通过类名访问
Son::func();
Son::Base::func();
Son::Base::func(10);
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
总结:非静态成员有两种访问方式,对象访问和类名访问。
4.6.7 多继承语法
在C++中允许一个类继承一个类
语法结构:class 子类 : 继承方式 父类1, 继承方式 父类2…
#include <iostream>
using namespace std;
class Base1
{
public:
Base1()
{
m_A = 10;
}
int m_A;
};
class Base2
{
public:
Base2()
{
m_A = 20;
}
int m_A;
};
class Son :public Base1, public Base2
{
public:
Son()
{
m_B = 30;
m_C = 40;
}
int m_B;
int m_C;
};
void test01()
{
Son s1;
cout << "sizeof(Son) = " << sizeof(Son) << endl;
//父类中出现同名成员,需加作用域区分
cout << "Base1 m_A = " << s1.Base1::m_A << endl;
cout << "Base2 m_A = " << s1.Base2::m_A << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
4.6.8 菱形继承
概念:
-
两个派生类继承同一个基类
-
又有某个类同时继承这两个派生类
1.羊继承了动物的数据,驼也继承了动物的数据,羊驼使用数据时,会产生二义性。
2.羊驼继承动物的数据两份,其实该数据只需要一份即可。
#include <iostream>
using namespace std;
class Animal
{
public :
int m_Age;
};
class Sheep :virtual public Animal //加上关键字virtual变成虚继承
{
};
//Animal类称为虚基类
class Camel :virtual public Animal //加上关键字virtual变成虚继承
{
};
class SheepCamel :public Sheep, public Camel
{
};
void test01()
{
SheepCamel sc;
sc.Sheep::m_Age = 18;
sc.Camel::m_Age = 18;
//菱形继承,两个父类拥有相同数据,需加作用域区分
cout << "sc.Sheep::m_Age = " << sc.Sheep::m_Age << endl;
cout << "sc.Camel::m_Age = " << sc.Camel::m_Age << endl;
cout << "sc.m_Age = " << sc.m_Age << endl;
//菱形继承导致数据有两份,资源浪费,可使用虚继承来解决该问题
}
int main()
{
test01();
system("pause");
return 0;
}
4.7 多态
多态的优点:
-
代码组织结构清晰
-
可读性强
-
利于前后期的扩展及维护
多态使用条件:父类指针或引用指向子类对象。
4.7.1 多态基本概念
多态是C++面向对象三大特征之一
多态分两类:
-
静态多态:函数重载与运算符重载属于静态多态,复用函数名
-
动态多态:派生类与虚函数实现运行时多态
静态多态与动态多态区别:
-
静态多态的函数地址早绑定 - 编译阶段确定函数地址
-
动态多态的函数地址晚绑定 - 运行阶段确定函数地址
//静态多态的函数地址早绑定 - 编译阶段确定函数地址
#include <iostream>
using namespace std;
class Afternoon
{
public:
void Drink()
{
cout << "Water" << endl;
}
};
class Person1 :public Afternoon
{
public:
void Drink()
{
cout << "Coffee" << endl;
}
};
class Person2 : public Afternoon
{
public:
void Drink()
{
cout << "Tea" << endl;
}
};
void doWork(Afternoon &af)
{
af.Drink();
}
void test01()
{
Person1 p1;
doWork(p1); //结果:Water
}
int main()
{
test01();
system("pause");
return 0;
}
//动态多态的函数地址晚绑定 - 运行阶段确定函数地址
#include <iostream>
using namespace std;
class Afternoon
{
public:
virtual void Drink() //虚函数
{
cout << "Water" << endl;
}
};
class Person1 :public Afternoon
{
public:
void Drink()
{
cout << "Coffee" << endl;
}
};
class Person2 : public Afternoon
{
public:
void Drink()
{
cout << "Tea" << endl;
}
};
//如果想要喝咖啡,需要让函数地址不提前绑定,在运行时绑定,地址晚绑定
void doWork(Afternoon& af)
{
af.Drink();
}
void test01()
{
Person1 p1;
doWork(p1); //结果:Coffee
Person2 p2;
doWork(p2); //结果:Tea
}
int main()
{
test01();
system("pause");
return 0;
}
补充:
动态多态满足条件:
-
继承关系
-
子类重写父类的虚函数
重写:函数返回值类型 函数名 参数列表完全一致。
4.7.2 纯虚函数和抽象类
父类中虚函数实现是无意义的,主要用来调用子类重写内容,我们可将虚函数改成纯虚函数。
语法结构:virtual 返回值类型 函数名 (参数列表) = 0 ;
当某个类中有了纯虚函数,那么也称该类为抽象类。
抽象类特点:
-
无法实例化对象
-
子类必须重写抽象类中纯虚函数,否则也属于抽象类
#include <iostream>
using namespace std;
class Base
{
public:
virtual void func() = 0; //纯虚函数
};
class Son : public Base //抽象类的子类必须重写父类中的纯虚函数,不然也属于抽象类
{
public:
virtual void func()
{
cout << "Son - func调用" << endl;
}
};
void test01()
{
//Base b1; //报错,抽象类无法实例化对象
//new Base; //报错,抽象类无法实例化对象
//Son s1; //类必须重写父类中的纯虚函数,否则无法实例化对象
Base* bs = new Son;
bs->func(); //结果:Son - func调用
}
int main()
{
test01();
system("pause");
return 0;
}
4.7.3 虚析构和纯虚析构
多态使用时,如子类有属性开辟到堆区上,那父类指针在释放时无法调用子类的析构代码
将父类的析构函数改为虚析构或者纯虚析构即可解决以上问题
虚析构和纯虚析构的共性:
-
可解决父类指针释放子类对象问题
-
都要有具体函数的实现
虚析构和纯虚析构的区别:
- 如果有纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法结构: virtual ~类名(){}
纯虚析构语法结构:virtual ~类名() = 0;
类名::类名(){}
#include <iostream>
#include <string>
using namespace std;
class Eat
{
public:
Eat()
{
cout << "Eat 构造函数调用" << endl;
}
virtual void Drinking() = 0;
//virtual ~Eat() //加上virtual,变成虚析构函数
//{
// cout << "Drinking 虚析构函数调用" << endl;
//}
virtual ~Eat() = 0;
};
Eat::~Eat() //纯虚析构,该类属于抽象类,无法实例化对象
{
cout << "Eat 纯虚析构函数调用" << endl;
}
class Coffee :public Eat
{
public:
Coffee(string feeding)
{
cout << "Coffee 构造函数调用" << endl;
m_Feeding = new string(feeding);
}
virtual void Drinking()
{
cout << *m_Feeding << "加入咖啡" << endl;
}
~Coffee()
{
cout << "Coffee 析构函数调用" << endl;
if (this->m_Feeding != NULL)
{
delete m_Feeding;
m_Feeding = NULL;
}
}
public:
string *m_Feeding;
};
void test01()
{
Eat* eat = new Coffee("牛奶");
eat->Drinking();
//通过父类指针释放,导致子类对象清理不干净,容易造成内存泄漏
//给基类加一个虚析构函数即可解决父类指针释放子类对象问题
delete eat;
}
int main()
{
test01();
system("pause");
return 0;
}
4.7.4 多态案例
案例一:制作计算器类
说明:分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类
普通写法:
#include <iostream>
#include <string>
using namespace std;
class calculator
{
public:
int operation(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;
}
else if (oper == "/")
{
return m_Num1 / m_Num2;
}
else
{
return 0;
}
}
int m_Num1;
int m_Num2;
};
void test01()
{
calculator calc;
calc.m_Num1 = 10;
calc.m_Num2 = 20;
cout << calc.m_Num1 << " + " << calc.m_Num2 << " = " << calc.operation("+") << endl;
cout << calc.m_Num1 << " - " << calc.m_Num2 << " = " << calc.operation("-") << endl;
cout << calc.m_Num1 << " * " << calc.m_Num2 << " = " << calc.operation("*") << endl;
cout << calc.m_Num1 << " / " << calc.m_Num2 << " = " << calc.operation("/") << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
多态技术:
#include <iostream>
using namespace std;
class AbstractCalculator //定义一个计算器抽象类
{
public:
virtual int operation()
{
return 0;
}
int m_Num1;
int m_Num2;
};
class AddCalculator :public AbstractCalculator //加法
{
int operation()
{
return m_Num1 + m_Num2;
}
};
class SubCalculator :public AbstractCalculator //减法
{
int operation()
{
return m_Num1 - m_Num2;
}
};
class MulCalculator :public AbstractCalculator //乘法
{
int operation()
{
return m_Num1 * m_Num2;
}
};
class divCalculator :public AbstractCalculator //除法
{
int operation()
{
return m_Num1 / m_Num2;
}
};
void test01()
{
//加法
AbstractCalculator* calc = new AddCalculator;
calc->m_Num1 = 10;
calc ->m_Num2 = 20;
cout << calc->m_Num1 << " + " << calc->m_Num2 << " = " << calc->operation() << endl; //30
delete calc; //用完销毁
//减法
calc = new SubCalculator;
calc->m_Num1 = 10;
calc->m_Num2 = 20;
cout << calc->m_Num1 << " - " << calc->m_Num2 << " = " << calc->operation() << endl; //-10
delete calc; //用完销毁
//乘法
calc = new MulCalculator;
calc->m_Num1 = 10;
calc->m_Num2 = 20;
cout << calc->m_Num1 << " * " << calc->m_Num2 << " = " << calc->operation() << endl; //200
delete calc; //用完销毁
//除法
calc = new divCalculator;
calc->m_Num1 = 10;
calc->m_Num2 = 20;
cout << calc->m_Num1 << " / " << calc->m_Num2 << " = " << calc->operation() << endl; //0
delete calc; //用完销毁
}
int main()
{
test01();
system("pause");
return 0;
}
案例二:制作冷饮
大致流程:煮水 - 冲泡 - 倒杯 - 加料 - 加冰
利用多态技术实现,提供抽象制作冷饮基类,提供子类制作拿铁和柠檬红茶
#include <iostream>
using namespace std;
class AbstractDrinking
{
public:
virtual void Boil() = 0; //煮水
virtual void Brew() = 0; //冲泡
virtual void PoutGlass() = 0; //倒杯
virtual void Feeding() = 0; //加料
virtual void AddIce() = 0; //加冰
void MakeDrink() //制作冷饮
{
Boil();
Brew();
PoutGlass();
Feeding();
AddIce();
}
};
class Latte :public AbstractDrinking //拿铁
{
public:
virtual void Boil() //煮水
{
cout << "煮矿泉水" << endl;
}
virtual void Brew() //冲泡
{
cout << "冲泡咖啡粉" << endl;
}
virtual void PoutGlass() //倒杯
{
cout << "倒入玻璃杯中" << endl;
}
virtual void Feeding() //加料
{
cout << "加入牛奶" << endl;
}
virtual void AddIce() //加冰
{
cout << "加入冰块" << endl;
}
};
class LemonBlackTea :public AbstractDrinking //柠檬红茶
{
public:
virtual void Boil() //煮水
{
cout << "煮矿泉水" << endl;
}
virtual void Brew() //冲泡
{
cout << "冲泡红茶" << endl;
}
virtual void PoutGlass() //倒杯
{
cout << "倒入玻璃杯中" << endl;
}
virtual void Feeding() //加料
{
cout << "加入柠檬片" << endl;
}
virtual void AddIce() //加冰
{
cout << "加入冰块" << endl;
}
};
void doWork(AbstractDrinking* abd) //制作函数
{
abd->MakeDrink();
delete abd;
}
void test01()
{
doWork(new LemonBlackTea);
cout << "-----------" << endl;
doWork(new Latte);
}
int main()
{
test01();
system("pause");
return 0;
}
案例三:组装电脑
说明:电脑主要组成部件、CPU、内存条、显示器。
-
将每个零件封装出抽象类,并提供不同厂商生产不同的零件,如Intel厂商和Nvidia厂商
-
创建电脑类提供让电脑工作的函数,并调用每个零件工作接口
-
测试时组装三台不同的电脑进行工作
#include <iostream>
using namespace std;
class CPU
{
public:
virtual void calculate() = 0;
};
class Memory
{
public:
virtual void storage() = 0;
};
class Display
{
public:
virtual void display() = 0;
};
class Computer
{
public:
Computer(CPU* cpu, Memory* mem, Display* dp)
{
m_cpu = cpu;
m_mem = mem;
m_dp = dp;
}
void doWork() //工作函数
{
//调用接口
m_cpu->calculate();
m_mem->storage();
m_dp->display();
}
~Computer()
{
if (m_cpu != NULL) //释放CPU部件
{
delete m_cpu;
m_cpu = NULL;
}
if (m_dp != NULL) //释放显示器部件
{
delete m_cpu;
m_dp = NULL;
}
if (m_mem != NULL) //释放内存条部件
{
delete m_cpu;
m_mem = NULL;
}
}
private:
CPU* m_cpu;
Memory* m_mem;
Display* m_dp;
};
class IntelCPU :public CPU
{
public:
virtual void calculate()
{
cout << "Intel - CPU 开始运行工作" << endl;
}
};
class NvidiaCPU :public CPU
{
public:
virtual void calculate()
{
cout << "Nvidia - CPU 开始运行工作" << endl;
}
};
class IntelDisplay :public Display
{
public:
virtual void display()
{
cout << "Intel - 显示器 开始显示工作" << endl;
}
};
class NvidiaDisplay :public Display
{
public:
virtual void display()
{
cout << "Nvidia - 显示器 开始显示工作" << endl;
}
};
class IntelMemory :public Memory
{
public:
virtual void storage()
{
cout << "Intel - 内存条 开始存储工作" << endl;
}
};
class NvidiaMemory :public Memory
{
public:
virtual void storage()
{
cout << "Nvidia - 内存条 开始存储工作" << endl;
}
};
void test01()
{
//第一台电脑零部件
/*CPU* intelCpu = new IntelCPU;
Display* intelDisplay = new IntelDisplay;
Memory* intelMem = new IntelMemory;*/
//创建第一台电脑
cout << "第一台电脑开始工作" << endl;
Computer* computer1 = new Computer(new IntelCPU, new IntelMemory, new IntelDisplay); //第一台电脑
computer1->doWork();
delete computer1;
cout << "----------------------" << endl;
cout << "第二台电脑开始工作" << endl;
Computer* computer2 = new Computer(new NvidiaCPU,new NvidiaMemory, new NvidiaDisplay);//第二胎电脑
computer2->doWork();
delete computer2;
cout << "----------------------" << endl;
cout << "第三台电脑开始工作" << endl;
Computer* computer3 = new Computer(new IntelCPU, new NvidiaMemory, new IntelDisplay); //第三台电脑
computer3->doWork();
delete computer3;
}
int main()
{
test01();
system("pause");
return 0;
}