(持续更新)c++中的继承、封装、多态
c++面向对象的三大特性为:继承、封装和多态
c++认为万事万物都皆为对象,对象上有其属性和行为
例如:
人可以作为对象,属性有姓名、年龄、身高、体重…,行为有走、跑、跳、吃饭、唱歌⋯
车也可以作为对象,属性有轮胎、方向盘、车灯…行为有载人、放音乐、放空调…
具有相同性质的对象,我们可以抽象称为类,人属于人类,车厲于车类
1.封装
1.1封装的意义
封装是c++面向对象的三大特性之一
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
封装意义一:
在设计类的时候,属性和行为写在一起,表现事物。
语法:class 类名{ 访问权限:属性 / 行为 };
实例代码:
#include <iostream> using namespace std; const double PI = 3.14; class Circle { public: int m_r; double calculate_ZC() { return 2 * PI * m_r; } }; int main() { //实例化:通过一个类,创建一个对象的过程 Circle c1; c1.m_r = 10; cout << "圆的周长为:" << c1.calculate_ZC() << endl; return 0; }
封装意义二:
类在设计时,可以把属性和行为放在不同的权限下,加以控制
类中的属性和行为,我们统一称为成员:
属性——成员属性、成员变量
行为——成员函数、成员方法
访问权限有三种:
(1)public 公共权限
(2)protected 保护权限
(3)private 私有权限
实例代码:
#include <iostream> #include <string> using namespace std; class Student { //属性 public: string m_name; int m_age; //行为 public: void setName(string name) { m_name = name; } void setAge(int age) { m_age = age; } void showStu() { cout << "学生姓名:" << m_name << endl << "学生年龄:" << m_age << endl; } }; int main() { Student s1; s1.setName("张三"); s1.setAge(18); s1.showStu(); }
1.2struct和class的区别
c++中struct和class唯一的区别就在于默认的访问权限不同
区别:
- struct默认权限为公共
- class默认权限为私有
1.3成员属性设置为私有
优点一:将所有成员属性设置为私有,可以自己控制读写权限
优点二:对于写权限,我们可以检测数据的有效性
实例代码:
#include<iostream> #include<string> using namespace std; class Person { private: string m_name; //姓名 可读可写 int m_age = 18; //年龄 只读 string m_addr; //地址 只写 public: void setName(string name) { m_name = name; } string getName() { return m_name; } int getAge() { return m_age; } void setAddr(string addr) { m_addr = addr; } private: void showStu() { cout << "姓名:" << m_name << "年龄:" << m_age << endl; } }; int main() { Person p1; p1.setName("张三"); cout << "姓名:" << p1.getName() << endl; cout << "年龄:" << p1.getAge() << endl; }
2.继承
2.1继承的意义
继承是c++面向对象的三大特性之一
子类继承父类
继承的好处:可以减少重复的代码
如:
class B:public class A;
A类称为 父类 或 基类
B类称为 子类 或派生类
派生类中的成员包含两大部分:
一类是从基类继承过来的,一类是自己增加的成员;
从基类继承过来的表现其共性,而新增的成员体现了其个性。
2.2继承的方式
继承的语法:class 子类 : 继承方式 父类
继承一共有三种:
- 公共继承
- 保护继承
- 私有继承
图示:
总结:
父类中的公共权限的成员,到子类中依然是公共权限;
父类中的保护权限的成员,到子类中依然是保护权限;
父类中的私有权限的成员,子类访问不到。
3.多态
3.1多态的意义
多态是c++面向对象的三大特性之一
多态分为两类:
- 静态多态:函数重载和运算符重载属于静态多态,复用函数名
- 动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态的区别:
- 静态多态的函数地址早绑定:编译阶段确定函数地址
- 动态多态的函数地址晚绑定:运行阶段确定函数地址
实例代码1:
#include <iostream> using namespace std; class Animal { public: //虚函数 virtual void speak() { cout << "动物在说话" << endl; } }; class Cat : public Animal { public: //重写 void speak() { cout << "小猫在说话" << endl; } }; class Dog : public Animal { public: void speak() { cout << "小狗在说话" << endl; } }; //执行说话的函数 void doSpeak(Animal *animal) { animal->speak(); } void test01() { //栈区开辟内存 Cat cat; doSpeak(&cat); Dog dog; doSpeak(&dog); } int main() { test01(); }
运行结果:
小猫在说话
小狗在说话
3.2纯虚函数和抽象类
在多态中,通常父类的虚函数的实现是毫无意义的,主要都是调用子类重写的内容。
因此可以将虚函数改为纯虚函数。
纯虚函数语法:virtual 返回值类型 函数名(参数列表)=0;
当类中有了纯虚函数,这个类也称为抽象类。
抽象类的特点:
- 无法实例化对象
- 子类必须重写抽象类中的纯虚函数,否则该子类也属于抽象类
实例代码2:
#include <iostream> using namespace std; class abstractCaculator { public: //纯虚函数 virtual int getResult() = 0; int m_Num1; int m_Num2; }; //加法计算器 class addCalculator : public abstractCaculator { public: int getResult() { return m_Num1 + m_Num2; } }; //减法计算器 class subCalculator : public abstractCaculator { public: int getResult() { return m_Num1 - m_Num2; } }; //乘法计算器 class mulCalculator : public abstractCaculator { public: int getResult() { return m_Num1 * m_Num2; } }; void test01() { //堆区开辟内存 abstractCaculator *abs = new addCalculator; abs->m_Num1 = 100; abs->m_Num2 = 200; cout << abs->m_Num1 << "+" << abs->m_Num2 << "=" << abs->getResult() << endl; delete abs; abs = new subCalculator; abs->m_Num1 = 300; abs->m_Num2 = 200; cout << abs->m_Num1 << "-" << abs->m_Num2 << "=" << abs->getResult() << endl; } int main() { test01(); }
运行结果:
100+200=300
300-200=100
实例代码3:
#include <iostream> using namespace std; class abstractDrink { 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 abstractDrink { public: //重写基类中的纯虚函数 void Boil() { cout << "煮水" << endl; } void Brew() { cout << "冲泡咖啡" << endl; } void PourInCup() { cout << "倒入杯中" << endl; } void PutSomething() { cout << "加入糖和牛奶" << endl; } }; class Tea : public abstractDrink { public: void Boil() { cout << "煮水" << endl; } void Brew() { cout << "冲泡茶叶" << endl; } void PourInCup() { cout << "倒入杯中" << endl; } void PutSomething() { cout << "加入柠檬" << endl; } }; void makeDrink(abstractDrink *abs) { abs->makeDrink(); } void test01() { //栈区开辟内存 Coffee cf; makeDrink(&cf); Tea t; makeDrink(&t); } int main() { test01(); }