1、静态多态:函数重载和运算符重载属于静态多态,复用函数名。静态多态的函数地址早绑定-编译阶段确定函数地址
2、动态多态:派生类和虚函数实现运行时多态。动态多态的函数地址晚绑定-运行阶段确定函数地址
1、有继承关系
2、子类重写父类的虚函数(virtual
)
重写:函数返回值类型、函数名、参数列表完全一致
class Animal{
public:
//虚函数
virtual void Speak() {
cout << "动物说话" << endl;
}
};
class Sheep :public Animal {
void Speak() {
cout << "羊在说话" << endl;
}
};
class Dog :public Animal {
void Speak() {
cout << "狗在说话" << endl;
}
};
//Speek没加virtual时地址早绑定,在编译阶段已经确定函数地址
void doSpeak(Animal& a) {//父类引用指向子类对象Animal &a=s1;
a.Speak();
}
void test() {
Sheep s1;
doSpeak(s1);
Dog d1;
doSpeak(d1);
}
3、父类的指针或引用,执行子类对象
指针占用四个字节。
父类:
子类:指针从父类继承
1、代码组织结构清晰
2、可读性强
3、利于前期和后期扩展和维护
4、开闭原则
//实现计算机抽象类
class AbstractC {
public:
int a;
int b;
virtual int getResult() {
return 0;
}
};
//加法
class Add :public AbstractC {
public:
int getResult(){
return a+b;
}
};
//-法
class Mul :public AbstractC {
public:
int getResult(){
return a - b;
}
};
//*法
class Cheng :public AbstractC {
public:
int getResult() {
return a * b;
}
};
///法
class Chu :public AbstractC {
public:
int getResult() {
return a / b;
}
};
void test() {
AbstractC* abc = new Add;
abc->a = 10;
abc->b=20;
cout << "加法:" << abc->a << "+" << abc->b << "=" << abc->getResult() << endl;
//用完销毁
delete abc;
abc = new Mul;
abc->a = 10;
abc->b = 20;
cout << "减法:" << abc->a << "-" << abc->b << "=" << abc->getResult() << endl;
//用完销毁
delete abc;
abc = new Cheng;
abc->a = 10;
abc->b = 20;
cout << "乘法:" << abc->a << "*" << abc->b << "=" << abc->getResult() << endl;
//用完销毁
delete abc;
abc = new Chu;
abc->a = 10;
abc->b = 20;
cout << "加法:" << abc->a << "/" << abc->b << "=" << abc->getResult() << endl;
//用完销毁
delete abc;
}
纯虚函数语法:virtual 返回值类型 函数名 (参数列表)=0;
当类中有了纯虚函数,这个类也称为抽象类
特点:无法实例化对象,子类必须重写抽象类中的纯虚函数,否则也属于抽象类。让子类必须重写父类中的纯虚函数,否则不能实例化对象。
class AbsDrink {
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 AbsDrink {
public:
virtual void Boil() {
cout << "煮咖啡" << endl;
}
virtual void Brew() {
cout << "冲水" << endl;
}
virtual void Pour() {
cout << "倒咖啡" << endl;
}
virtual void Put() {
cout << "加小料" << endl;
}
};
class Tea :public AbsDrink {
public:
virtual void Boil() {
cout << "煮清泉" << endl;
}
virtual void Brew() {
cout << "冲茶水" << endl;
}
virtual void Pour() {
cout << "倒茶" << endl;
}
virtual void Put() {
cout << "加茶叶" << endl;
}
};
void doWork(AbsDrink* a) {
a->make();
delete a;
}
void test() {
doWork(new Coffee);
cout << "--------------------------" << endl;
doWork(new Tea);
}
多态使用时,若子类中有属性开辟到堆区中,父类指针在释放时无法调用到子类的析构代码,就需要将的父类中的析构函数改为虚析构和纯虚析构
1、可以解决父类指针释放子类对象
2、都需要有具体的函数实现
3、如果是纯虚析构,该类属于抽象类,无法实例化对象
父类指针在析构时,不会调用子类中析构函数,导致子类如果由堆区属性,出现了内存泄漏,虚析构可以解决
虚析构语法:virtual ~类名(){}
纯虚析构语法:virtual ~类名()=0;类名::~类名(){}
1、虚析构或纯虚析构是用来解决通过父类指针释放子类对象
2、如果子类没有堆区数据,可以不写
3、拥有纯虚析构函数的类也属于抽象类
class Animal {
public:
//虚函数
virtual void Speak() {
cout << "动物说话" << endl;
}
Animal() {
cout << "动物的构造函数" << endl;
}
/*虚析构,抽象类,无法实例化对象
virtual ~Animal() {
cout << "动物的析构函数" << endl;
}*/
//纯虚析构 需要声明也需要实现
virtual ~Animal() = 0;
};
Animal::~Animal() {
}
class Sheep :public Animal {
public:
string* name;
Sheep(string _name) {
name = new string(_name);
cout << "羊的构造函数" << endl;
}
void Speak() {
cout << "羊在说话" << endl;
}
~Sheep() {
if (name != NULL) {
cout << "羊的析构函数" << endl;
delete name;
name = NULL;
}
}
};
void doSpeak(Animal& a) {
a.Speak();
}
void test() {
Animal *a=new Sheep("羊");
a->Speak();
//父类指针在析构时,不会调用子类中析构函数,导致子类如果由堆区属性,出现了内存泄漏
delete a;
}