Fork me on GitHub

C++-多态篇


什么是多态

简单来说,相同对象收到不同消息或不同的对象接收到相同消息时产生不同的动作

静态多态和动态多态

静态多态也称之为早绑定

1
2
3
4
5
6
class Rect
{
public:
int calcArea(int width);
int calcArea(int width,int height);
};

这种重载,在编译之时就知道要使用哪个函数,称之为静态多态

动态多态也称之为晚绑定

这里写图片描述

必须以封装和继承作为基础,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Shape
{
public:
double calcArea()
{
cout<<"calcArea"<<endl;
return 0;
}
};

class Circle:public Shape
{
public:
Circle(double r);
double calcArea();
private:
double m_dR;
};

class Rect:public Shape
{
public:
Circle(double width,double height);
double calcArea();
private:
double m_dWidth;
double m_dHeight;
};


int main(void)
{
Shape *shape1 = new Circle(4.0);
Shape *shape2 = new Rect(3.0,5.0);
shape1->calcArea();
shape2->calcArea();
delete shape1;
delete shape2;

return 0;
}

这个程序运算出来的结果肯定和我们想要的不一样,它只会输出两个calcArea,而不会分别输出对应的面积
这个时候就需要把calcArea()定义为虚函数,这就是动态多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Shape
{
public:
virtual double calcArea() // 虚函数
{
cout<<"calcArea"<<endl;
return 0;
}
};

class Circle:public Shape
{
public:
Circle(double r);
virtual double calcArea();
private:
double m_dR;
};

class Rect:public Shape
{
public:
Circle(double width,double height);
virtual double calcArea();
private:
double m_dWidth;
double m_dHeight;
};

int main(void)
{
Shape *shape1 = new Circle(4.0);
Shape *shape2 = new Rect(3.0,5.0);
shape1->calcArea();
shape2->calcArea();
delete shape1;
delete shape2;

return 0;
}

虚析构函数

多态中存在的问题

  • 内存泄露

    delete 父类对象时,只会析构父类对象,当delete 子类对象使,不仅会析构子类对象还会析构其父对象
    如果在动态多态中用父类指针指向子类,当成员中需要在堆中申请内存的时候,这时用delete 父类指针就会造成内存泄漏

这个时候就需要用虚析构函数

virtual ~Shape();

virtual的限制

  1. virtual只能修饰类中的成员函数,不能修饰全局函数
  2. virtual不能用于修饰类的静态成员函数
  3. virtual不能修饰内联函数
  4. virtual不能修饰构造函数

隐藏vs覆盖

隐藏:就是父子关系,同名函数
覆盖:就是动态多态中含有虚函数

纯虚函数

1
2
3
4
5
6
7
class Shape
{
public:
virtual double calcArea() // 虚函数
{return 0;}
virtual double calcPerimeter() = 0; // 纯虚函数
};

抽象类

含有纯虚函数的类称为抽象类

抽象类不能实例化,抽象类的子类只有把抽象类中的所有纯虚函数实现之后才能实例化

接口类

在类中仅含有纯虚函数的类称为接口类

运行时类型识别 RTTI

1
2
3
4
5
6
7
8
9
10
11
void doSomething(Flyable *obj)
{
obj->takeoff();
cout<<typeid(*obj).name()<<endl;
if(typeid(*obj) == typeid(Bird))
{
Bird *bird = dynamic_cast<Bird *>(obj);
bird->foraging();
}
obj->land();
}

dynamic_cast<>只能用于指针和引用之间的转换
typeid返回一个type_info对象的引用
如果想要通过基类的指针获得派生类的数据类型,基类必须带有虚函数

坚持原创技术分享,您的支持将鼓励我继续创作
-------------本文结束感谢您的阅读-------------
0%