> 文章列表 > 多 态

多 态

多 态

1多态的基本概念

多态是C++面向对象三大特性之一

多态分为两类

静态多态: 函数重载和运算符重载属于静态多态,复用函数名

动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

静态多态的函数地址早绑定–--编译阶段确定函数地址

动态多态的函数地址晚绑定–--运行阶段确定函数地址

动态多态满足条件

1、有继承关系

2、子类重写父类的虚函数

动态多态使用

父类的指针或者引用 指向子类对象

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 test345() {

Cat cat;

doSpeak(cat);

Dog dog;

doSpeak(dog);

}

2.纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容

因此可以将虚函数改为纯虚函数

纯虚函数语法: virtual 返回值类型 函数名(参数列表) = 0 ;

当类中有了纯虚函数,这个类也称为抽象类

抽象类特点:

不允许实例化对象

子类必须重写抽象类中的纯虚函数,否则也属于抽象类

// 纯虚函数和抽象类

class HeyY {

public:

//纯虚函数

//只要有一个纯虚函数,这个类称为抽象类

//抽象类特点:

//1、无法实例化对象

virtual void func() = 0;

//2、抽象类的子类 必须要重写父类的纯虚函数,否则也属于抽象类

};

class HeyW : public HeyY {

virtual void func()

{

cout << "Son using func " << endl;

}

};

void test346() {

//Base b;

HeyY * hy = new HeyW;

hy->func();

}

3.虚析构和纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

解决方式: 将父类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:

·可以解决父类指针释放子类对象

·都需要有具体的函数实现

虚析构和纯虚析构区别:

如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名()=0;

类名 : : ~类名(){}

总结:

1.虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

2.如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

3.拥有纯虚析构函数的类也属于抽象类

class DW

{

public :

DW() {

cout << "DW构造函数调用" << endl;

}

// 利用虚析构可以解决父类指针 释放子类对象时不干净的问题

/*virtual ~DW() {

cout << "DW析构函数调用" << endl;

}*/

//纯虚函数

virtual void speak() = 0;

//纯虚析构 需要声明也需要实现

// 有了纯虚析构之后,这个类也属于抽象类,无法实例化对象

virtual ~DW() = 0;

};

DW:: ~DW() {

cout << "DW纯析构函数调用" << endl;

}

//鱼类

class Fish:public DW

{

public:

string * m_name;

Fish(string name) {

cout << "Fish构造函数调用" << endl;

m_name = new string(name);//开辟在堆区,并用指针维护

}

virtual void speak() {

cout <<*m_name<< "fish 在冒泡" << endl;

}

~Fish() {

if (m_name != NULL) {

cout << *m_name << "Fish析构函数调用" << endl;

delete m_name;

m_name = NULL;

}

}

};

void test90() {

DW *dw = new Fish("liyu");

dw->speak();

//父类指针在析构时候 不会调用子类中析构函数,导致子类如果有堆区属性,出现内存泄漏

delete dw;

}

多 态