普通算法题不太涉及的C++知识点(四):继承,多态
1. 继承:
1.1 继承的基本语法:
/*
//不使用继承:
class java{
public:
void header(){
cout << 1 << endl;
}
void footer(){
cout << 2 << endl;
}
void left(){
cout << 3 << endl;
}
void content(){
cout << 4 << endl;
}
};
class python{
public:
void header(){
cout << 1 << endl;
}
void footer(){
cout << 2 << endl;
}
void left(){
cout << 3 << endl;
}
void content(){
cout << 4 << endl;
}
};
*/
//使用继承:减少重复的代码
//语法: class 子类 : 继承方法 父类
class base{
public:
void header(){
cout << 1 << endl;
}
void footer(){
cout << 2 << endl;
}
void left(){
cout << 3 << endl;
}
};
//java
class java : public base{
public:
void content(){
cout << 4 << endl;
}
};
//python
class python : public base{
public:
void content(){
cout << 5 << endl;
}
};
void test1(){
java j;
j.header();
j.footer();
j.left();
j.content();
}
int main(){
test1();
return 0;
}
1.2 继承方式:
一共三种:公共继承,保护继承,私有继承。
\ | 父类成员类型 | public | protected | private |
---|---|---|---|---|
子类继承方法 | \ | \ | \ | \ |
public | \ | public | protected | 不可访问 |
protected | \ | protected | protected | 不可访问 |
private | \ | private | private | 不可访问 |
1.3 继承中的对象模型:
从父类继承过来的成员,哪些属于子类对象?
class base{
public:
int m_a;
protected:
int m_b;
private: //仍会被子类继承
int m_c;
};
class son : public base{
public:
int m_d;
};
void test1(){
cout << sizeof(son) << endl; //输出16
//因为在父类中所有非静态成员属性都会被子类继承
//父类中的私有成员只是被编译器隐藏了
}
int main(){
test1();
return 0;
}
1.4 继承中构造和析构顺序:
父类先构造,子类后构造;子类先析构,父类后析构。
1.5 继承的同名成员处理方式:
访问子类同名成员,直接访问;访问父类同名成员,需要加作用域。
class base{
public:
base(){
m_a = 100;
}
void func(){
cout << 1 << endl;
}
int m_a;
};
class son : public base{
public:
son(){
m_a = 200;
}
void func(){
cout << 2 << endl;
}
int m_a;
};
//同名成员属性
void test1(){
son s1;
cout << s1.m_a << endl; //输出200
cout << s1.base::m_a << endl; //输出100
}
//同名成员函数
void test2(){
son s2;
s2.func(); //输出2
s2.base::func(); //输出1
}
int main(){
test1();
test2();
return 0;
}
1.6 继承的静态同名成员处理方式:
和非静态一样。访问子类同名成员,直接访问;访问父类同名成员,需要加作用域。
1.7 多继承语法:
class son : public base1, public base2{
};
1.8 菱形继承:
两个派生类继承同一个基类,又有某个类同时继承这两个派生类。
class base{};
class base1 : virtual public base{};
class base2 : virtual public base{};
//使用虚继承解决菱形继承问题
class son : public base1, public base2{
};
2. 多态:
2.1 多态的基本语法:
静态多态:函数重载,运算符重载,复用函数名;
动态多态:派生类和虚函数实现运行时多态;
静态多态和动态多态的区别:
静态多态的函数地址早绑定——编译阶段确定函数地址;
动态多态的函数地址晚绑定——运行阶段确定函数地址。
class animal{
public:
virtual void speak(){
cout << 1 << endl;
}
};
class cat : public animal{
public:
void speak(){
cout << 2 << endl;
}
}
//地址早绑定,所以调用的是animal的speak函数
void dospeak(animal &animal1){ //允许父子之间的类型转换
animal1.speak();
}
//地址晚绑定,才可以调用cat的speak函数
void test(){
cat cat1;
dospeak(cat1); //animai类的speak不加virtual输出1,加了输出2
}
int main(){
test();
return 0;
}
2.2 多态原理:(?)
class animal{
public:
//虚函数 vfptr指向vftable(虚函数表)
virtual void speak(){
cout << 1 << endl;
}
};
2.3 多态案例一:计算器类
普通写法:如果想要拓展新的功能,需要修改源码。
但在开发中提倡开闭原则:对扩展开放,对修改关闭。
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 test(){
calculator c1;
c1.m_num1 = 10;
c1.m_num2 = 20;
cout << c1.getresult("+") << endl;
cout << c1.getresult("-") << endl;
cout << c1.getresult("*") << endl;
}
int main(){
test();
return 0;
}
多态技术:
//实现计算器抽象类
class abstract_calculator{
public:
virtual int getresult(){
return 0;
}
int m_num1;
int m_num2;
};
class add : public abstract_calculator{
public:
int getresult(){
return m_num1 + m_num2;
}
};
class sub : public abstract_calculator{
public:
int getresult(){
return m_num1 - m_num2;
}
};
class mul : public abstract_calculator{
public:
int getresult(){
return m_num1 * m_num2;
}
};
void test(){
abstract_calculator * abc = new add;
abc->m_num1 = 10;
abc->m_num2 = 20;
cout << abc->getresult() << endl;
delete(abc);
abc = new sub;
abc->m_num1 = 10;
abc->m_num2 = 20;
cout << abc->getresult() << endl;
delete(abc);
}
int main(){
test();
return 0;
}
2.4 纯虚函数和抽象类:
在多态中,通常父类中的虚函数是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为纯虚函数。
含有纯虚函数的类称为抽象类。抽象类无法实例化对象,子类必须重写抽象类的纯虚函数。
class base{
public:
//纯虚函数:
virtual void func() = 0;
};
class son : public base{
public:
virtual void func(){
cout << 1 << endl;
}
};
2.5 多态案例二:制作饮品
抽象类制作饮品基类,子类制作咖啡和茶叶。
class drinking{
public:
virtual void boil() = 0;
virtual void brew() = 0;
virtual void pour() = 0;
virtual void put() = 0;
void make(){
boil();
brew();
pour();
put();
}
};
class coffee : public drinking{
public:
virtual void boil(){
cout << 1.1 << endl;
}
virtual void brew(){
cout << 1.2 << endl;
}
virtual void pour(){
cout << 1.3 << endl;
}
virtual void put(){
cout << 1.4 << endl;
}
};
class tea : public drinking{
public:
virtual void boil(){
cout << 2.1 << endl;
}
virtual void brew(){
cout << 2.2 << endl;
}
virtual void pour(){
cout << 2.3 << endl;
}
virtual void put(){
cout << 2.4 << endl;
}
};
void makedrink(drinking *d){
d->make();
delete d;
}
void test(){
makedrink(new coffee);
}
int main(){
test();
return 0;
}
2.6 虚析构和纯虚析构:
多态使用时,如果子类有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码。
解决方法:将父类中的析构函数改为虚析构或纯虚析构。
class animal{
public:
//虚析构
virtual ~animal(){
}
//纯虚析构
//virtual ~animal() = 0;
virtual void speak() = 0;
};
//纯虚析构
//animal::~animal(){
// cout << 1 << endl;
//}
class cat : public animal{
public:
cat(string name){
m_name = new string(name);
}
~cat(){
if(m_name!=NULL){
delete m_name;
m_name = NULL;
}
}
virtual void speak(){
cout << 1 << endl;
}
string *m_name;
};
void test(){
animal *a = new cat("Tom");
a->speak();
delete a; //直接delete父类指针,不会调用子类的析构函数,如果有使用过new,会发生内存泄漏。
//将父类析构函数改为虚析构就可以解决此问题。
}
int main(){
test();
return 0;
}
2.7 多态案例三:电脑组装
电脑主要组成部件为CPU,显卡,内存条。
#include <iostream>
using namespace std;
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 *c, videocard *vc, memory *mem){
m_c = c;
m_vc = vc;
m_mem = mem;
}
~computer(){
if(m_c!=NULL){
delete m_c;
m_c = NULL;
}
if(m_vc!=NULL){
delete m_vc;
m_vc = NULL;
}
if(m_mem!=NULL){
delete m_mem;
m_mem = NULL;
}
}
void work(){
m_c->calculate();
m_vc->display();
m_mem->storage();
}
private:
cpu *m_c;
videocard *m_vc;
memory *m_mem;
};
class intelcpu : public cpu{
public:
virtual void calculate(){
cout << 1 << endl;
}
};
class intelvc : public videocard{
public:
virtual void display(){
cout << 2 << endl;
}
};
class intelmem : public memory{
public:
virtual void storage(){
cout << 3 << endl;
}
};
void test(){
cpu *c1 = new intelcpu;
videocard * vc1 = new intelvc;
memory *mem1 = new intelmem;
computer *com1 = new computer(c1, vc1, mem1);
com1->work();
delete com1;
}
int main(){
test();
return 0;
}