多态
多态性:不同对象受到相同的消息时,产生不同的动作
-
两种描述:
-
具有不同功能的函数可以用同一个函数名
-
指向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为
-
-
多态的实现
-
函数重载
-
运算符重载
-
虚函数
-
-
C++中的多态性可以分为四类
-
通用多态
- 参数多态:与类属函数和类属类相关联(函数模板和类模板就是这种多态)
- 包含多态:研究类族中定义于不同类中的同名成员函数的多态行为(主要是通过虚函数来实现的)
-
专用多态
- 重载多态:普通函数及类的成员函数的重载多属于重载多态(如,函数重载、运算符重载等)
- 强制多态:指一个变元的类型加以变化,以符合一个函数或操作的要求(例如加法运算符在进行浮点数与整形数相加时,首先进行强制转换,把整形数变为浮点数再相加的情况)
-
-
从实现角度分:
-
静态多态性——函数重载、运算符重载
-
动态多态性——继承、虚函数
-
C++中,多态的实现和联编有关
- 联编是把函数名和函数体的程序代码连接(联系)在一起的过程
- 编译时的多态:静态联编,在编译阶段完成
- 静态联编时,系统用实参和形成进行匹配,对于同名的重载函数便根据参数上的差异进行区分,然后进行联编。从而实现多态性。
- 运行时的多态:动态联编,在运行阶段完成
- 当程序调用到某一函数时,才去寻找和连接其程序代码,对面向对象的程序设计而言,就是当对象接收到某一消息时,采取寻找和连接对应的方法
-
一般而言,编译型语言都采用静态联编,而解释性语言都采用动态联编。
- 纯粹的面向对象程序设计语言由于其执行机制是消息传递,所以只能采用动态联编。
而为了保持C语言的高效性,C++仍是编译型的,仍采用静态联编;C++设计了“虚函数”的机制,解决了这个问题。
C++实际上是采用了静态联编和动态联编相结合的联编方法。
- 在C++中,编译时多态性主要是通过函数重载和运算符重载实现的。
- 运行时多态性主要是通过虚函数来实现的。
-
Example 0. virtual function
#include <iostream>
using namespace std;
class Shape
{
protected:
int width, height;
public:
Shape(int a = 0, int b = 0) { width = a, height = b; }
int area()
{
cout << "Parent class area: " << endl;
return 0;
}
};
class Rectangle : public Shape
{
public:
Rectangle(int a = 0, int b = 0) : Shape(a, b) {}
int area()
{
cout << "Rectangle class area: " << endl;
return width * height;
}
};
class Triangle : public Shape
{
public:
Triangle(int a = 0, int b = 0) : Shape(a, b) {}
int area()
{
cout << "Triangle class area: " << endl;
return (width * height / 2); //这里int型,有点问题
}
};
int main()
{
Shape *shape;
Rectangle rect(10, 7);
Triangle tri(10, 5);
shape = ▭
shape->area();
shape = &tri;
shape->area();
return 0;
}
/*
Parent class area:
Parent class area:
*/
#include <iostream>
using namespace std;
class Shape
{
protected:
int width, height;
public:
Shape(int a = 0, int b = 0) { width = a, height = b; }
virtual int area() //虚函数
{
cout << "Parent class area: " << endl;
return 0;
}
};
class Rectangle : public Shape
{
public:
Rectangle(int a = 0, int b = 0) : Shape(a, b) {}
int area()
{
cout << "Rectangle class area: " << endl;
return width * height;
}
};
class Triangle : public Shape
{
public:
Triangle(int a = 0, int b = 0) : Shape(a, b) {}
int area()
{
cout << "Triangle class area: " << endl;
return (width * height / 2); //这里int型,有点问题
}
};
int main()
{
Shape *shape;
Rectangle rect(10, 7);
Triangle tri(10, 5);
shape = ▭
shape->area();
shape = &tri;
shape->area();
return 0;
}
/*
Rectangle class area:
Triangle class area:
*/
Example 1. Point class,静态多态性,运算符重载
#include <iostream>
using namespace std;
class Point
{
protected:
float x, y;
public:
Point(float x = 0, float y = 0) : x(x), y(y) {} //有默认参数的构造函数
void setPoint(float a, float b) { x = a, y = b; }
float getX() const { return x; }
float getY() const { return y; }
friend 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(8.5, 6.8);
cout << "p(new):" << p << endl;
return 0;
}
/*
x=3.5,y=6.4
p(new):[8.5,6.8]
*/
#include <iostream>
using namespace std;
#define PI 3.14159
class Point
{
protected:
float x, y;
public:
Point(float x = 0, float y = 0) : x(x), y(y) {} //有默认参数的构造函数
void setPoint(float a, float b) { x = a, y = b; }
float getX() const { return x; }
float getY() const { return y; }
friend ostream &operator<<(ostream &output, const Point &p)
{
output << "[" << p.x << "," << p.y << "]" << endl;
return output;
}
};
class Circle : public Point
{
private:
float radius;
public:
Circle(float x = 0, float y = 0, float r = 0) : Point(x, y), radius(r) {}
void setRadius(float r) { radius = r; }
float getRadius() const { return radius; }
float area() const { return PI * radius * radius; }
friend ostream &operator<<(ostream &output, const Circle &c)
{
output << "Center=[" << c.x << "," << c.y << "], r="
<< c.radius << ", area=" << c.area() << endl;
return output;
}
};
int main()
{
Circle c(3.5, 6.4, 5.2);
cout << "original circle: x=" << c.getX()
<< ", y=" << c.getY()
<< ", r=" << c.getRadius()
<< ", area=" << c.area() << endl;
c.setRadius(7.5);
c.setPoint(5, 5);
cout << "new circle: " << c;
Point &pRef = c;
cout << "pRef: " << pRef << endl;
return 0;
}
/*
original circle: x=3.5, y=6.4, r=5.2, area=84.9486
new circle: Center=[5,5], r=7.5, area=176.714
pRef: [5,5]
*/
#include <iostream>
using namespace std;
#define PI 3.14159
class Point
{
protected:
float x, y;
public:
Point(float x = 0, float y = 0) : x(x), y(y) {} //有默认参数的构造函数
void setPoint(float a, float b) { x = a, y = b; }
float getX() const { return x; }
float getY() const { return y; }
friend ostream &operator<<(ostream &output, const Point &p)
{
output << "[" << p.x << "," << p.y << "]" << endl;
return output;
}
};
class Circle : public Point
{
private:
float radius;
public:
Circle(float x = 0, float y = 0, float r = 0) : Point(x, y), radius(r) {}
void setRadius(float r) { radius = r; }
float getRadius() const { return radius; }
float area() const { return PI * radius * radius; }
friend ostream &operator<<(ostream &output, const Circle &c)
{
output << "Center=[" << c.x << "," << c.y << "], r="
<< c.radius << ", area=" << c.area() << endl;
return output;
}
};
class Cylinder : public Circle
{
protected:
float height;
public:
Cylinder(float x = 0, float y = 0, float r = 0, float h = 0) : Circle(x, y, r), height(h) {}
void setHeight(float h) { height = h; }
float getHeight() const { return height; }
float area() const { return 2 * Circle::area() + 2 * PI * Circle::getRadius() * height; }
float volume() const { return Circle::area() * height; }
friend ostream &operator<<(ostream &output, const Cylinder &cy)
{
output << "Center=[" << cy.x << "," << cy.y << "], r="
<< cy.getRadius() << ", h=" << cy.height
<< ", area=" << cy.area() << ", volume=" << cy.volume() << endl;
return output;
}
};
int main()
{
Cylinder cy1(3.5, 6.4, 5.2, 10);
cout << "original cylinder: x=" << cy1.getX()
<< ", y=" << cy1.getY()
<< ", r=" << cy1.getRadius()
<< ", h=" << cy1.getHeight()
<< ", area=" << cy1.area()
<< ", volume=" << cy1.volume() << endl;
cy1.setHeight(15);
cy1.setRadius(7.5);
cy1.setPoint(5, 5);
cout << "new cylinder: " << cy1;
Point &pRef = cy1;
cout << "pRef as a Point: " << pRef;
Circle &cRef = cy1;
cout << "cRef as a Circle: " << cRef;
return 0;
}
/*
original cylinder: x=3.5, y=6.4, r=5.2, h=10, area=496.623, volume=849.486
new cylinder: Center=[5,5], r=7.5, h=15, area=1060.29, volume=2650.72
pRef as a Point: [5,5]
cRef as a Circle: Center=[5,5], r=7.5, area=176.714
*/