继承
思想与Java差不多
基本语法
- 语法:
class 子类 : 继承方式 父类
继承方式
- 将访问权限,上升到保护权限,上升到更高的私有权限
继承哪些部分
- 继承过程中,即使权限不能访问,也会全部继承下来(非静态属性是共有的,不会继承)
构造和析构顺序
-
- 先构造父类
-
- 构造子类
-
- 析构子类
-
- 析构父类
子类和父类出现同名成员
若子类和父类,有相同名字的成员(属性/方法)。
- 加作用域就完事
- 同名属性值:
- 同名函数:
- 无论是属性还是方法,都会优先用子类的,即使重载才有可能溯源到父类
子类和父类出现同名成员(静态)
处理方式一致
- 访问方式:
- 直接访问子类;
- 通过子类访问父类。
多继承(一个类继承多个类)
语法: class 子类 : 继承方式 父类1 , 继承方式 父类2...
。如果有同名成员出现,加作用域区分。
- 两个父类有相同属性值:
- 使用方式:
菱形继承
一些问题:
解决:
- 虚继承:子类在继承父类时,加上关键字 virtual。
- 下面的 sheep 和 tuo 都在虚拟继承Animal类。这时,Animal类被称为 虚基类 ,
- 虚继承就是使用虚类指针 指向 虚类表,多个子类共享继承的成员,不会混乱
- 虚基类的底层:
再举个例子:
-
下面来用存储结构说明一下:
-
左边是非虚继承,A类继承了2个 int a 的值。
-
右边是虚继承,只有一份 int a 的值,两个virtual继承的子类B和C,其实不是真的继承,只是用表指向共有的a值
多态
基本用法
-
小贴士:静态绑定在程序运行中不可更改,记住这个
-
在下面准备两个类,都有speak方法
没有产生希望的 ”小猫在说话”:
- 形参这里
Animal &animal
等同于Animal & animal = cat
- 函数内
animal.speak
应该是:小猫 才对。但是因为草绑定,绑定的是父类Animal类。
解决方式:虚函数。可以实现地址晚绑定,从而实现动态多态
- 虚函数speak写在父类里,直到确认某个对象,才绑定地址
- virtual允许父子类之间的函数重载(重写也行)
多态条件:
- 有继承
- 子类要重写从父类继承来的虚函数(类似Java的抽象函数强制重写)
使用条 件:
- 参数:父类的指针/引用,执行子类对象
多态内部原理
-
父类和子类都有虚函数表
-
虚函数表内部记录当前作用域中虚函数(speak)的地址
-
当子类重写父类的虚函数,子类的虚函数表中内容就会被覆盖
-
多态的关键是虚函数指针和虚函数表
抽象类
父类:抽象计算器
子类:加/减/乘/除法计算器
多态:getResult声明为虚函数,期待各种子类重写
多态方便维护某个加/减/乘/除计算器
纯虚函数 抽象类
和Java很像:在父类中声明纯虚函数,强制子类重写该函数。有纯虚函数的类叫抽象类,不能实例对象。
多态案例
定义抽象类:
重写两个子类内部的方法
使用多态接口,传入父类的指针,调用传入子类的 重写的方法。
虚析构 和 纯虚析构
用小猫和Animal的父类子类举例:
其构造函数中,在堆区new一个字符串,m_Name指向这个字符串。
发现cat的析构函数没有执行,也就是说m_Name没有被释放
修改父类中的析构函数为虚析构:
总结:
组装电脑的例子
- 创建三个大类:CPU,GPU,Memory
//三个零件 抽象类:
//CPU基类/父类
class CPU {
public:
virtual void caculate() = 0;
};
class GPU {
public:
virtual void show() = 0;
};
class Memory {
public:
virtual void storage() = 0;
};
- 创建电脑类,通过指针获取构造函数传入的零件,调用零件内的功能。
// 电脑类:
class Computer {
public: //记得加权限
//构造时传入三个指针,并保存在本类中
Computer(CPU* cpu, GPU* gpu, Memory* mem) {
this->m_cpu = cpu;
this->m_gpu = gpu;
this->m_mem = mem;
}
void dowork() {
//分别调用传入的三个类,对应的方法
m_cpu->caculate();
m_gpu->show();
m_mem->storage();
}
//用来释放下面的三个零件指针
~Computer() {
if (m_cpu != NULL) {
delete m_cpu;
m_cpu = NULL;
}
if (m_gpu != NULL) {
delete m_gpu;
m_gpu = NULL;
}
if (m_mem != NULL) {
delete m_mem;
m_mem = NULL;
}
}
// 三个零件指针
private:
CPU* m_cpu;
GPU* m_gpu;
Memory* m_mem;
};
- 创建这两个品牌的零件,重写内部功能
//两个具体厂商:
class IntelCPU :public CPU {
public:
//重写抽象类中的虚函数
void caculate() {
cout << "IntelCPU" << endl;
}
};
class IntelGPU :public GPU {
public:
void show() {
cout << "IntelGPU" << endl;
}
};
class IntelMem :public Memory {
public:
void storage() {
cout << "IntelMem" << endl;
}
};
class LenCPU :public CPU {
public:
void caculate() {
cout << "LenCPU" << endl;
}
};
class LenGPU :public GPU {
public:
void show() {
cout << "LenGPU" << endl;
}
};
class LenMem :public Memory {
public:
void storage() {
cout << "LenMem" << endl;
}
};
- 创建对象,用指针定位,再把指针传入构造函数,并调用对象功能。
void test01() {
IntelCPU* icpu = new IntelCPU;
IntelGPU* igpu = new IntelGPU;
IntelMem* imem = new IntelMem;
//也可以:
//CPU* icpu = new IntelCPU;
//GPU* igpu = new IntelGPU;
//Memory* imem = new IntelMem;
Computer* computer1 = new Computer(icpu, igpu, imem);
computer1->dowork();
delete computer1; //释放new出来的对象
}