C++多态之虚函数、动态关联

1. 多态的两种机制

1.1机制1

派生类的指针可以赋给基类的指针
通过基类的指针调用基类和派生类中的同名虚函数(一种特殊的成员函数)时:
(1):若该指针指向一个基类的对象,那么就调用基类的虚函数
(2):若该指针指向一个派生类的对象,那么被调用的是派生类的虚函数

1.2机制2

派生类的对象可以赋给基类的引用
通过该基类的引用调用基类和派生类的同名虚函数时:
(1):若该引用引用的是一个基类的对象,那么调用的是基类的虚函数
(2):如果引用的是一个派生类的对象,那么调用的是派生类的虚函数

1.3实例

#include <iostream>
using namespace std;
class Shape{
public:
    Shape() { 
        cout << "constructor function:" << endl; 
        cout << "excute Shape()" << endl; 
    }
    virtual void print() { cout << "excute virtual print() at class Shape" << endl; }
};
class Point :public Shape {
public:
    Point() {
        cout << "constructor function:" << endl; 
        cout << "excute Point()" << endl; 
    }
    virtual void print() { cout << "excute virtual print() at class Point" << endl; }
};
class Circle :public Point {
public:
    Circle() { 
    cout << "constructor function:" << endl;
    cout << "excute Circle()" << endl; 
    }
    virtual void print() { cout << "excute virtual print() at class Circle" << endl; }
};
int main(){
    Shape shape1; 
    Point point1; 
    Circle circle1;
    Shape *ptshape1=&shape1;
    Point *ptpoint1 = &point1;
    Circle *ptcircle1 = &circle1;
    ptshape1->print();//调用shape1.print()
    ptshape1 = ptpoint1;//派生类指针赋给基类指针
    ptshape1->print();//调用point1.print()
    ptshape1 = ptcircle1;//派生类指针赋给基类指针
    ptshape1->print();//调用circle1.print()
    return 0;
}

这里写图片描述

2.虚函数与动态联编

2.1虚函数

虚函数是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。

2.2动态联编

一条函数调用语句在编译时无法确定调用哪个函数,运行到该语句时才确定调用哪个函数,这种机制称之为动态联编(或动态关联)

2.3实例

#include <iostream>
using namespace std;
class Shape {
public:
    virtual float area() const { return 0.0; }  //虚函数
    virtual float volume() const { return 0.0; }//虚函数
    virtual void shapeName() const = 0;//纯虚函数

};
class Point :public Shape {
protected:
    float x, y;
public:
    Point(float = 0, float = 0);//声明构造函数
    void SetPoint(float, float);
    float getX() const { return x; }
    float getY() const { return y; }
    virtual void shapeName() const { cout << "Point: "; }//重新定义虚函数 virtual可有可无
                                                         //函数声明的const,表示该函数不会修改该类的任何成员数据的值,称为常量成员函数
    friend ostream & operator <<(ostream &, const Point &);//运算符重载

};
Point::Point(float a, float b) {
    x = a;
    y = b;
}
void  Point::SetPoint(float a, float b) {
    x = a;
    y = b;
}
ostream & operator<<(ostream &output, const Point &p) {
    output << "[" << p.x << "," << p.y << "]";
    return output;
}
class Circle :public Point {
public:
    Circle(float x = 0, float y = 0, float r = 0);//声明构造函数
    void setRadius(float); //set R
    float getRadius() const;//get the value of Radius
    virtual float area() const;  //对虚函数进行再定义
    virtual void shapeName() const { cout << "Circle: "; }//对虚函数进行再定义
protected:
    float radius;

};
//定义Circle类的函数
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;
}
float Circle::area() const {
    return  3.14*radius*radius;
}
ostream &operator<<(ostream &output, const Circle &c) {
    output << "[" << c.getX() << "," << c.getY() << "],r=" << c.getRadius();
    return output;
}
void myfunc(Shape *pt) {
    pt->shapeName();
    //编译时无法确定调用的是Shape.shapeName()、Point.shapeName()还是Circle.shapeName()
    //因为编译时无法确定形参会对应哪个类的对象
}
int main()
{
    Point point(2.1, 3.4);         //new Point类对象
    Circle circle(2.3, 4.5, 5.0);  //new Circle类对象
    point.shapeName();  //用对象名建立静态关联
    cout << point << endl;//输出点数据

    circle.shapeName();  用对象名建立静态关联
    cout << circle << endl;//输出圆数据

    Shape *pshape;//定义基类指针
    pshape = &point;  //指向Point类的对象point
    cout << "\n\n" << endl;
    pshape->shapeName();  //建立动态关联
    myfunc(pshape);

    cout << "x=" << point.getX() << " , y=" << point.getY() << "\n area=" << pshape->area()
        << "\nvolume=" << pshape->volume() << "\n\n"; //output information about point

    pshape = &circle;  //指向Circle类的对象circle
    cout << "\n\n" << endl;
    pshape->shapeName();  //建立动态关联
    myfunc(pshape);
    cout << "x=" << circle.getX() << " , y=" << circle.getY() << ",r=" << circle.getRadius() << "\n area=" << pshape->area()
        << "\nvolume=" << pshape->volume() << "\n\n"; //output information about point
    cout << "hello word" << endl;
    return 0;
}

运行结果:
这里写图片描述

3.多态的作用

多态的本质
(1):父类定义共同接口,子类不同实现
(2):通过父类以相同的方式操作不同子类的行为
在面向对象的程序设计中使用多态
(1):能够增强程序的可扩充性
(2):程序需要修改或增加功能的时候,需要改动或增加的代码较少

4.覆盖与虚函数访问机制对比

这里写图片描述

5.多态的实现:虚函数表

(I):每一个有虚函数的类(或有虚函数的类的派生类都有一个虚函数表,该类的任何对象中都存放着虚函数表的指针。
(II):虚函数表中列出该类的虚函数地址。多出来的4个字节就是用来存放虚函数表的地址。

5.1实例

#include <iostream>
using namespace std;
class Shape {
public:
    int a=9;
    virtual void print() { cout << "excute virtual print() at class Shape" << endl; }
};
class Point :public Shape {
public:
    int b = 10;
    virtual void print() { cout << "excute virtual print() at class Point" << endl; }
};
int main() {
    Shape shape1;
    Point point1;
    cout << "sizeof(int)=" << sizeof(int) << endl;
    cout << "sizeof(Shape)=" << sizeof(Shape) << endl;
    cout << "sizeof(Point)=" << sizeof(Point) << endl;
    return 0;
}

这里写图片描述

6.构造函数与析构函数中调用虚函数

(I)在构造函数中和析构函数中调用虚函数时:他们调用的函数是自己类或基类(如果自己类中没有定义该虚函数)定义的函数,不会等到运行时才决定调用自己的还是派生类的同名虚函数。
(II)在普通成员函数中调用虚函数,则是动态联编,是多态

6.1实例

#include <iostream>
using namespace std;
class Shape {
public:
    Shape() {
        cout << "excute constructor function: Shape()" << endl;
    }
    virtual void print() { cout << "excute virtual  Shape.print() at class Shape" << endl; }
};
class Point :public Shape {
public:
    Point() {
        cout << "excute constructor function: Point()" << endl;
        print();
    }
    virtual void print() { cout << "excute virtual Point.print() at class Point" << endl; }
};
class Circle :public Point {
public:
    Circle() {
        cout << "excute constructor function:  excute Circle()" << endl;
        print();
    }
    virtual void print() { cout << "excute virtual  Circle.print() at class Circle" << endl; }
};
int main() {
    cout << "new Point class : point1" << endl << endl;
    Point point1;
    cout << endl << "new Circle class : circle1" << endl << endl;
    Circle circle1;
    Point *ptpoint1 = &point1;
    ptpoint1->print();// excute point1.print();
    ptpoint1 = &circle1;
    ptpoint1->print();// excute circle1.print();
    return 0;
}

运行结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值