C++核心 DAY4
多态
多态的基本概念
首先多态分为静态多态和动态多态
静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
动态多态: 派生类和虚函数实现运行时多态静态多态和动态多态区别:
静态多态的函数地址早绑定 - 编译阶段确定函数地址
动态多态的函数地址晚绑定 - 运行阶段确定函数地址
在这个案例中,
class animal
{
public:
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 &a)
{
a.speak();
}
void test()
{
cat c;
dospeak(c);
dog g;
dospeak(g);
}
我们只需要改动一行,那么输出就正确了
class animal
{
public:
virtual void speak()
{
cout<<"动物在说话"<<endl;
}
};
在函数面前加入virtual,那么这个函数就变成虚函数了。 那么比那一起在编译的时候就不能确定函数调用,要到运行的时候才知道
多态的满足条件
1,有继承关系 2 子类重写父类中的虚函数
多态使用:父类指针或引用指向子类对象
案例一
其实这个案例就可以发现,父类中的虚函数根本没有调用过
父类指针指向子类对象,所以我们是caculator *p;
class caculator
{
public:
virtual int getanswe()
{
return 0;
}
int a;
int b;
};
class add :public caculator
{
public:
int getanswe()
{
return a+b;
}
};
class sub :public caculator
{
public:
int getanswe()
{
return a-b;
}
};
class mul :public caculator
{
public:
int getanswe()
{
return a*b;
}
};
void test()
{
caculator *p1=new add;
p1->a=10;
p1->b=10;
cout<<p1->getanswe()<<endl;
delete p1;
p1=new sub;
p1->a=10;
p1->b=10;
cout<<p1->getanswe()<<endl;
delete p1;
p1=new mul;
p1->a=10;
p1->b=10;
cout<<p1->getanswe()<<endl;
delete p1;
}
纯虚函数与抽象类
这里先了解概念?
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;
当类中有了纯虚函数,这个类也称为抽象类
无法实例化对象 这个意思是例如 animal a;这个就是不合法的
子类函数必须重写纯虚函数,不然子类也是抽象类。
class base
{
public:
virtual void func()=0;
};
class son:public base
{
void func()
{
cout<<"func调用"<<endl;
}
};
void test()
{
base *base=NULL;
base=new son;
base->func();
delete base;
}
如果写这个就会报错,因为无法实例化对象。

案例二
class base
{
public:
virtual void boil()=0;
virtual void brew()=0;
virtual void pour()=0;
virtual void add()=0;
void dosome()
{
boil();brew();pour();add();
}
};
class coffee:public base
{
void boil()
{
cout<<"煮农夫山泉"<<endl;
}
void brew()
{
cout<<"冲泡咖啡"<<endl;
}
void pour()
{
cout<<"倒入咖啡杯"<<endl;
}
void add()
{
cout<<"加入牛奶和咖啡"<<endl;
}
};
class tea:public base
{
void boil()
{
cout<<"煮山泉水"<<endl;
}
void brew()
{
cout<<"冲泡茶叶"<<endl;
}
void pour()
{
cout<<"倒入茶杯"<<endl;
}
void add()
{
cout<<"加入柠檬"<<endl;
}
};
void test()
{
base *b=NULL;
b=new coffee;
b->dosome();
cout<<"-------------------------------------"<<endl;
delete b;
b=new tea;
b->dosome();
delete b;
}
虚析构与纯虚析构
可以看到这里结果都没有走到cat的析构函数。因为这里发生了多态,我们使用的是父类animal的指针去指向子类对象。代码正常运行是要test函数跑完再进行析构。结果我们已经delete animal这个指针了
父类指针在析构的时候不会去调用子类的析构
class animal
{
public:
animal()
{
cout<<"animal构造函数"<<endl;
}
virtual void speak()=0;
~animal()
{
cout<<"animal析构函数"<<endl;
}
};
class cat:public animal
{
public:
cat(string name)
{
cout<<"cat构造函数"<<endl;
m_name=new string(name);
}
virtual void speak()
{
cout<<"小猫在说话"<<endl;
}
~cat()
{
if(m_name!=NULL)
{
delete m_name;
m_name=NULL;
}
cout<<"cat析构函数"<<endl;
}
string *m_name;
};
void test()
{
animal *an=new cat("617");
an->speak();
delete an;
}
如果将父类中的析构函数改为虚析构,OK了
virtual ~animal()
{
cout<<"animal析构函数"<<endl;
}
纯虚析构
纯虚析构和纯虚函数一样的写法 但是和纯虚函数一样一定要加上实现,纯虚函数实在子类实现,纯虚析构是在类外实现,虚析构也要写代码实现。
因为析构函数你只要写了那就会走你写的这个,所以一定要写代码。
有了纯虚析构之后,这个类也属于抽象类,无法实例化
virtual ~animal()=0;
animal::~animal()
{
cout<<"animal析构函数"<<endl;
}案例三
代码运行逻辑: 首先是要组装一台电脑,一台电脑有三个零件:内存条,CPU,GPU;这里我们将电脑运行了什么CPU,GPU,内存条写在电脑这个类中,只需要传入什么牌子的让他自己输出就好。
第二,定义了CPU,GPU,内存条这三个类,里面只有纯虚函数,这是抽象基类,让他们的各个品牌的子类去实现具体函数。各个品牌的子类先继承了父类;
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 *mm)
{
m_cpu=cpu;
m_gpu=gpu;
m=mm;
}
void work()
{
m_cpu->caculate();
m_gpu->show();
m->storage();
}
~computer()
{
if(m_cpu!=NULL)
{
delete m_cpu;
m_cpu=NULL;
}
if(m_gpu!=NULL)
{
delete m_gpu;
m_gpu=NULL;
}
if(m!=NULL)
{
delete m;
m=NULL;
}
}
private:
CPU* m_cpu;
GPU* m_gpu;
memory *m;
};
class InterCPU: public CPU
{
public:
void caculate()
{
cout<<"InterCPU正在计算"<<endl;
}
};
class InterGPU:public GPU
{
public:
void show()
{
cout<<"InterGPU正在显示"<<endl;
}
};
class AMDCPU:public CPU
{
public:
void caculate()
{
cout<<"AMDCPU正在计算"<<endl;
}
};
class AMDGPU:public GPU
{
public:
void show()
{
cout<<"AMDGPU正在显示"<<endl;
}
};
class ACER:public memory
{
public:
void storage()
{
cout<<"ACER内存条正在储存"<<endl;
}
};
class Lenovo:public memory
{
public:
void storage()
{
cout<<"Lenovo内存条正在储存"<<endl;
}
};
void test()
{
CPU *Intercpu=new InterCPU;
GPU* Intergpu=new InterGPU;
memory* acer=new ACER;
cout<<"第一台电脑正在工作"<<endl;
computer *c1=new computer(Intercpu,Intergpu,acer);
c1->work();
delete c1;
cout<<"--------------------------"<<endl;
cout<<"第二台电脑正在工作"<<endl;
computer *c2=new computer(new AMDCPU,new AMDGPU,new ACER);
c2->work();
delete c2;
cout<<"--------------------------"<<endl;
cout<<"第三台电脑正在工作"<<endl;
computer *c3=new computer(new AMDCPU,new InterGPU,new Lenovo);
c3->work();
delete c3;
}