C++学习-多态性与虚函数

多态性

概念:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。
作用:可以实现一个接口,多种方法
应用:多态性分为静态多态性和动态多态性,静态多态性即编译时的多态性,通过函数重载实现;动态多态性是运行时才确定操作所作用的对象,动态多态性通过虚函数(virtual function)实现;


例子:
建立一个Point(点)类,包含数据成员x,y(坐标点)。以它为基类,派生出一个Circle(圆)类,增加数据成员r(半径),再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类,再增加数据成员h(高)。要求编写程序,重载运算符“<<”和“>>”,使之能用于输出以上类对象。

对于一个比较大的程序,应当分成若干步骤进行。先声明基类,再声明派生类,逐级进行,分步调试。

//首先实现基类point
#include <iostream>
using namespace std;

class point
{
public:
    point(float x=0, float y=0);//构造函数,初始化坐标(0,0)
    void setPoint(float, float);
    float getx() const {return x;}
    float gety() const {return y;}
    friend ostream & operator<<(ostream &, const point &);

protected:
    float x, y;
};

void point::setPoint(float a, float b)
{
    x = a;
    y = b;
}
point::point(float a, float b)
{
    x = a;
    y = b;
}
ostream & operator<<(ostream & output, const point & p)
{
    output << "[" << p.x << "," << p.y << "]" << endl;
    return output;
}
int main()
{
    point p(3.5, 6.4); 
    cout<<"x="<<p.getx()<< "   y=" << p.gety()<<endl;
    p.setPoint(1.1,3.2);
    cout << "pnew = " << p << endl;
}
//输出结果
x=3.5   y=6.4
pnew = [1.1,3.2]
//声明派生类circle
//派生类

class circle:public point
{
public:
    circle(float x=0, float y=0, float r=0);//构造函数
    void setRadius(float);//设置半径值
    float getRadius() const;
    float area() const;//计算圆面积
    friend ostream  &operator<<(ostream &, const circle &);//重载运算符<<,输入参数为一个输出流引用及circle对象引用

private:
    float radius;

};
//定义构造函数,对圆心坐标和半径初始化
circle::circle(float a, float b, float r):point(a,b),radius(r)
{

}

void circle::setRadius(float r)
{
    radius = r;
}
float circle::getRadius() const
{
    return radius;
}

ostream & operator<<(ostream & output, const circle & c)
{
    output << "Center = [" << c.x << "," << c.y<< "], r = " << c.radius << ", area = " << c.area() << endl;
    return output;
}

float circle::area() const
{
    float radius = getRadius();
    return 3.14159*radius*radius;
}

将int main(){}更改为:

int main()
{
    point p(3.5, 6.4); //p
    cout<<"x="<<p.getx()<< "   y=" << p.gety()<<endl;
    p.setPoint(1.1,3.2);
    cout << "pnew = " << p << endl;
    circle c(2.5, 6.4, 4.3);//建立circle对象,并给出圆心和半径
    cout << "origina circle:" << c.getx() << ", y = " << c.gety() << ", r = " << c.getRadius() << ", area = " << c.area() << endl;
    c.setRadius(7.0);
    c.setPoint(2.0, 2.0);
    cout << "new circle:" << c;
    point &pRef = c;
    cout << "pRef:" << pRef;
    return 0;
}
//运行结果
x=3.5   y=6.4
pnew = [1.1,3.2]

origina circle:2.5, y = 6.4, r = 4.3, area = 58.088
new circle:Center = [2,2], r = 7, area = 153.938
pRef:[2,2]

接下来再从派生类circle派生出cylinder类

//cylinder类
//增加高度属性
//声明circle的派生类cylinder
class cylinder:public circle
{
public:
    cylinder(float x=0, float y=0, float r=0, float h=0);//构造函数
    void setHeight(float);//设置圆柱高
    float getHeight() const;//获取圆柱高度
    float volume() const;//计算圆柱体积
    friend ostream & operator<<(ostream &, const cylinder &);

private:
    float height;//圆柱高度
};

cylinder::cylinder(float a, float b, float r, float h)
    :circle(a, b, r),height(h)
{

}

void cylinder::setHeight(float h)
{
    height = h;
}

float cylinder::getHeight() const
{
    return height;
}

float cylinder::volume() const
{
    float height = getHeight();
    float area = circle::area();
    return (area*height);
}
//重载运算符 <<
ostream & operator<<(ostream & output, const cylinder & cy)
{
    output << "Center = [" << cy.x << cy.y << "]" << ", r = " << cy.getRadius() << ", h = " << cy.height
           << "\narea = " << cy.area() << ", volume = " << cy.volume() << endl;
    return output;
}

将int main(){}更改为:

int main()
{
    //point test
    point p(3.5, 6.4); //p
    cout<<"x="<<p.getx()<< "   y=" << p.gety()<<endl;
    p.setPoint(1.1,3.2);
    cout << "p-new = " << p << endl;

    //circle test
    circle c(2.5, 6.4, 4.3);//建立circle对象,并给出圆心和半径
    cout << "origina circle:x = " << c.getx() << ", y = " << c.gety() << ", r = " << c.getRadius() << ", area = " << c.area() << endl;
    c.setRadius(7.0);
    c.setPoint(2.0, 2.0);
    cout << "new circle:" << c;
    point &pRef = c;
    cout << "pRef:" << pRef;

    //cylinder test
    cylinder cy(3.2, 7.6, 7.5, 4.3);//建立cylinder对象,并给出圆心,半斤,高度
    cout << "original cylinder:x = " << cy.getx() << ", y = " << cy.gety() << ", r = " << cy.getRadius() << ", h = " << cy.getHeight() << endl;
    cy.setPoint(1.0, 1.0);
    cy.setRadius(3.0);
    cy.setHeight(6.5);
    cout << "new cylinder:" << cy;
    point &pRef1 = cy;
    cout << pRef1;//作为点输出
    circle &pRef2 = cy;
    cout << pRef2;//作为圆输出
    return 0;
}

输出:

x=3.5   y=6.4
p-new = [1.1,3.2]

origina circle:x = 2.5, y = 6.4, r = 4.3, area = 58.088
new circle:Center = [2,2], r = 7, area = 153.938
pRef:[2,2]
original cylinder:x = 3.2, y = 7.6, r = 7.5, h = 4.3
new cylinder:Center = [11], r = 3, h = 6.5
area = 28.2743, volume = 183.783
[1,1]
Center = [1,1], r = 3, area = 28.2743

上例的静态多态性是运算符重载引起的。可以看到,在编译时编译系统即可以判定应调用哪个重载运算符函数。稍后将在此基础上讨论动态多态性问题。


动态多态性通过虚函数实现:
虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

猜你喜欢

转载自blog.csdn.net/delete_09/article/details/81779897