C++之多态(静态多态+动态多态+虚函数+虚析构函数+多态原理[未完待续])

多态(静态多态+动态多态)
多态是面向对象的三大特征(封装,继承,多态)之一。
教科书定义:指相同对象接收不同消息或不同对象接到相同消息产生不同的动作。简单来说就是当发出一条命令时,不同的对象接收到同样的命令时,所做出的动作是不同的。

静态多态(早绑定)
如下代码,两个一样的函数名,但是参数不同,在调用时,程序会根据参数不同调用不同函数。因为程序很早就把这种情况编译进去,这就情况就叫静态多态。

class Rect
{
public:
    int calcArea(int width);
    int calcArea(int width, int height);
};

int main()
{
    Rect rect;
    rect.calcArea(10);
    rect.calcArea(10, 20);
    return 0;
}

动态多态(晚绑定)
动态多态必须以封装和继承为基础,动态多态起码要有两个类,一个是子类,一个是父类,当然也可以有三个类,只有有三个类的时候我们的动态多态才能表现的比较明显,以下代码为例

class Circle :public Shape
{
public:
    Circle(double r);
    double calcArea();
private:
    double m_dR;
};
double Circle::calArea()
{
    return 3.14*m_dR*m_dR;
};
double Rect::calcArea()
{
    return m_dWidth*m_dHeight;
};
int main()
{
    Shape *shape1 = new Circle(4,.0);
    Shape *shape2 = new Rect(3.0,5.0);
    shape1->calcArea();//用到的都是父类的计算面积,屏幕上会打印出claArea()
    shape2->calcArea();
    //....
    return 0;
}

可以利用virtual虚函数来实现多态。如下代码,输出的就是计算的圆的面积

class Shape
{
public:
    virtual double calcArea()//虚函数
    {
        cout << "clacArea" << endl;
        return 0;
    }
};

class Circle :public Shape
{
public:
    Circle(double r);
    virtual double calcArea();//virtual不是必须,系统会自动加一个virtual
private:
    double m_dR;
};

但是动态多态容易引起内存泄漏的问题,如下代码
代码1:

class Shape
{
public:
    Shape();
    virtual double calcArea();
};

class Circle :public Shape
{
public:
    Circle(int x, int y, double r);
    ~Circle();
    virtual double calcArea();
private:
    double m_dR;
    Coordinate *m_pCenter; //多定义了一个指针的数据成员
};

Circle::Circle(int x, int y, double r)
{
    m_pCenter = new Coordinate(x, y);
    m_dR = r;
}

Circle::~Circle
{
    delete m_pCenter;
    m_pCenter = NULL;
}

int main()
{
    Shape *shape1 = new Circle(3, 5, 4.0);
    shape1->calArea();
    delete shape1;//想借助父类的指针去销毁子类的指针时,会出问题,只执行父类的析构
    shape1 = NULL;
    return 0;
}

如上代码,我们在Circle中多定义了一个成员指针*m_pCenter,当我们在main()函数中delete shape1时,由于它是父类的指针,销毁时他只会调用父类的析构函数,而不会调用子类的析构函数,这就造成了内存的泄漏。这时我们要引入虚析构函数,同样是用virtual关键字修饰析构函数。代码示例如下:
代码1.1

class Shape
{
public:
    Shape();
    virtual ~shape();//虚析构函数
    virtual double calcArea();

};

class Circle :public Shape
{
public:
    Circle(int x, int y, double r);
    virtual ~Circle();
    virtual double calcArea();
private:
    double m_dR;
    Coordinate *m_pCenter; //多定义了一个指针的数据成员
};

这个时候我们再用代码1中的main()函数,这个时候我们再使用delete,如果我们这个时候在delete后面跟上父类指针的时候,父类指针指向的是哪个对象,那么哪个对象的析构函数就先得以执行,然后再执行父类的。这样就保证了内存不会泄漏。

同样vitual的使用也有一些限制
1.普通函数(全局函数)不能是虚函数,要是类中的成员函数。
2.静态成员函数不能是虚函数
3.内联函数不能是虚函数
4.构造函数不能是虚函数

虚函数的实现原理
先介绍一下函数指针:之前我们知道如果通过指针指向对象,我们叫他对象指针,那么指针当然也可以指向函数,函数的本质是一段二进制代码,它写在内存当中,我们可以通过指针来指向这段代码的开头,那么计算机就会从开头一直执行,直到函数的结尾,然后再返回。函数的指针和普通的指针本质上时一样的,如下图
这里写图片描述

class Shape
{
public:
    virtual double calcArea()//虚函数
    {
        return 0;
    }
protected:
    int m_iEge;
};

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

我们看如上的代码,此时的虚函数如何实现呢?(等我搞懂了再说—–

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rocky0429

一块也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值