1、多态的基本概念
成员函数加上关键字virtual后Animal里多了个指针vfptr,指向vftable,里边储存了Animal& animal的地址。
如果子类重写成员函数,那么复制过来的vftable会储存重写的类,即储存的是Cat& cat的地址。
#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;
}
};
//动态多态满足条件
//1、有继承关系
// 2、子类重写父类的虚函数
//重写的概念:函数返回值类型 函数名 参数列表 都完全一致称为重写
// 动态多态的使用
// !!!用父类的指针或者引用 指向子类对象,见41行
void dospeak(Animal& animal) //Animal& animal = cat;
{
animal.Speak();
}
void test()
{
Cat cat;
dospeak(cat);
Dog dog;
dospeak(dog);
}
int main()
{
test();
return 0;
}
2、动态多态使用的几种方法
!用父类的指针或者引用 指向子类对象!
方法一:父类的引用指向子类对象
特点:这里创建一个对象去调用dospeak的引用参数
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& animal = cat;
{
animal.Speak();
}
void test()
{
Cat cat; //这里创建一个对象去调用dospeak的引用参数
dospeak(cat);
Dog dog;
dospeak(dog);
}
方法二:父类的指针指向子类对象
特点:用指针的只需要 “new 数据类型 ”就可以,()里为占位参数,可加可不加。
!!用完后记得释放!!
class abstractcalculator
{
public:
virtual int getresult()
{
return 0;
}
int m_A;
int m_B;
};
class Add :public abstractcalculator
{
virtual int getresult()
{
return m_A + m_B;
}
};
void test()
{
//多态使用条件
//父类指针或者引用指向子类对象
abstractcalculator* abc = new Add();
abc->m_A = 100;
abc->m_B = 100;
cout << abc->m_A << " + " << abc->m_B << " = " << abc->getresult() << endl;
//用完后记得释放
delete abc;
注意:如果拥有多个大同小异相关功能的虚函数时,用另外一个虚函数来包括所有的虚函数。
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:
virtual void Boil()
{
cout << "加入开水" << endl;
}
virtual void Brew()
{
cout << "冲泡咖啡" << endl;
}
virtual void Pourincup()
{
cout << "倒入杯中" << endl;
}
virtual void Putsomething()
{
cout << "加入糖和牛奶" << endl;
}
};
void dowork(abstractDrink* abs)
{
abs->makeDrink(); //这个虚函数包括了取余的虚函数
delete abs; //用完记得释放
}
void test()
{
dowork(new Coffee);
dowork(new Tea);
}
3、虚析构函数和纯虚析构函数
#include<iostream>
using namespace std;
class Animal
{
public:
Animal()
{
cout << "Animal的构造函数" << endl;
}
//虚析构
//virtual ~Animal()
//{
// cout << "Animal的析构函数" << endl;
//}
//!!!注意,纯虚析构函数和虚析构函数只能有一个,有了其之后子类才能执行析构函数——释放堆区数据
//纯虚析构函数的声明
//!!!有了纯虚析构之后,即使没有纯虚函数,这个类也属于抽象类,无法实例化对象
virtual ~Animal() = 0;
//纯虚函数
virtual void speak() = 0;
};
//纯虚构函数的实现
Animal::~Animal()
{
cout << "Animal的纯虚析构函数" << endl;
}
class Cat:public Animal
{
public:
Cat(string name)
{
cout << "Cat的构造函数" << endl;
m_Name = new string(name);
}
virtual void speak()
{
cout << *m_Name << "小猫在说话" << endl;
}
~Cat()
{
if (m_Name != NULL)
{
delete m_Name;
m_Name = NULL;
}
cout << "Cat的析构函数" << endl;
}
string* m_Name;
};
void test()
{
Animal* a = new Cat("Tom");
a->speak();
//父类指针在析构时候,不会调用子类中的析构函数,导致如果子类有堆区属性,出现内存泄露
//解决方法为虚析构
delete a;
}
int main()
{
test();
return 0;
}
4、组装电脑案例
#include<iostream>
using namespace std;
//创建抽象类
class CPU
{
public:
virtual void caculate() = 0;
};
//创建抽象类
class Videocard
{
public:
virtual void show() = 0;
};
//创建抽象类
class Memory
{
public:
virtual void storage() = 0;
};
创建电脑类
class Computer
{
public:
//利用构造函数初始化零件
Computer(CPU* cpu, Videocard* vc, Memory* me)
{
this->cpu = cpu;
this->me = me;
this->vc = vc;
}
~Computer()
{
if (this->cpu != NULL)
{
delete this->cpu;
this->cpu = NULL;
}
if (this->vc != NULL)
{
delete this->vc;
this->vc = NULL;
}
if (this->me != NULL)
{
delete this->me;
this->me = NULL;
}
}
//提供全部零件工作接口
void work()
{
cpu->caculate();
vc->show();
me->storage();
}
private:
//因为零件是纯虚函数不能直接创建对象 必须用指针创建 而它们又放在电脑类的构造中 所以要在电脑类中析构内存释放堆区数据
CPU* cpu;
Videocard* vc;
Memory* me;
};
class Intercpu: public CPU
{
public:
virtual void caculate()
{
cout << "英特尔的CPU开始计算了" << endl;
}
};
class Intervideocard : public Videocard
{
public:
virtual void show()
{
cout << "英特尔的显示器开始显示了" << endl;
}
};
class Intermemory : public Memory
{
public:
virtual void storage()
{
cout << "英特尔的内存条开始储存了" << endl;
}
};
class Lenovocpu : public CPU
{
public:
virtual void caculate()
{
cout << "Lenovo的CPU开始计算了" << endl;
}
};
class Lenovovideocard : public Videocard
{
public:
virtual void show()
{
cout << "Lenovo的显示器开始显示了" << endl;
}
};
class Lenovomemory : public Memory
{
public:
virtual void storage()
{
cout << "Lenovo的内存条开始储存了" << endl;
}
};
void test()
{
CPU* intercpu = new Intercpu;
Videocard* vc = new Intervideocard;
Memory* me = new Intermemory;
Computer* c1 = new Computer(intercpu, vc, me);
c1->work();
delete c1;
cout << "--------------------------" << endl;
cout << "第二台电脑" << endl;
Computer* c2 = new Computer(new Lenovocpu, new Lenovovideocard, new Lenovomemory);
c2->work();
delete c2;
cout << "--------------------------" << endl;
cout << "第三台电脑" << endl;
Computer* c3 = new Computer(new Intercpu, new Lenovovideocard, new Intermemory);
c3->work();
delete c3;
}
int main()
{
test();
return 0;
}