C++学习笔记——05 C++的多态性


🌿前言:本系列笔记是主要是对于谭浩强的c++程序设计的学习笔记再加上一些我自己的理解。如果有误欢迎大家指出。

建议是有基础的同学快速入门,或者复习用

一、什么是多态性

1.静态多态性 编译时的多态性 函数重载和运算符重载

2.动态多态性 运行时的多态性 虚函数

二、一个典型的例子

Part1

#include<iostream>
using namespace std; 
class Point
{
	public:
		Point(float x=0,float y=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;
};
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<<"]"<<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;
}

Part2

#include<iostream>
using namespace std; 
class Point
{
	public:
		Point(float x=0,float y=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;
};
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<<"]"<<endl;
	return output;
}
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&);
	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;}
float Circle::area()const
{
	return 3.14159*radius*radius;
}
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:\nx="<<c.getX()<<",y="<<c.getY()<<",r="<<c.getRadius()<<",area="<<c.area()<<endl;
	c.setRadius(7.5);
	c.setPoint(5,5);
	cout<<"new circle:\n"<<c;
	Point &pRef=c;
	cout<<"pRef:"<<pRef;
	return 0;
}

Part3

#include<iostream>
using namespace std; 
class Point
{
	public:
		Point(float x=0,float y=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;
};
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<<"]"<<endl;
	return output;
}
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&);
	protected:
	    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;}
float Circle::area()const
{
	return 3.14159*radius*radius;
}
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
{
	public:
		Cylinder(float x=0,float y=0,float r=0,float h=0);
		void setHeight(float);
		float getHeight() const;
		float area() const;
		float volume() const;
		friend ostream &operator<<(ostream &,const Cylinder&);
	protected:
		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::area() const
{
	return 2*Circle::area()+2*3.14159*radius*height;
}
float Cylinder::volume() const
{
	return Circle::area()*height;
}
ostream & operator<<(ostream &output,const Cylinder& cy)
{
	output<<"Center=["<<cy.x<<","<<cy.y<<"],r="<<cy.radius<<",h="<<cy.height<<"\narea="<<cy.area()<<",volume="<<cy.volume()<<endl;
	return output;
}
int main()
{
	Cylinder cy1(3.5,6.4,5.2,10);
	cout<<"original cylinder:\nx="<<cy1.getX()<<",y="<<cy1.getY()<<",r="<<cy1.getRadius()<<",h="<<cy1.getHeight()<<"\narea="<<cy1.area()<<",volume="<<cy1.volume()<<endl;
	cy1.setHeight(15);
	cy1.setRadius(7.5);
	cy1.setPoint(5,5);
	cout<<"\nnew cylinder:\n"<<cy1;
	Point &pRef=cy1;
	cout<<"\npRef as a point:"<<pRef;
	Circle &cRef=cy1;
	cout<<"cRef as a Circle:"<<cRef;
	return 0;
}

三、利用虚函数实现动态多态性

1.虚函数的作用
  • 类中无法重复定义,如果定义了会进行同名覆盖

  • 虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。(如果不定义虚函数是无法通过基类指针去调用派生类对象中的该成员函数)

  • 虚函数的使用方法:

    (1)在基类中用virtual声明成员函数为虚函数。在类外定义虚函数时,不必再在虚函数名前加virtual。

    (2)在派生类中重新定义时需要保持函数名、函数类型、函数参数个数和类型一致,如果没有重新定义,派生类会继承直接基类的虚函数。

    (3)定义一个指向基类对象的指针变量,并使它指向同类一族中需要调用该函数的对象

    (4)通过该指针变量调用此虚函数

#include<iostream>
#include<string>
using namespace std;
class Student
{
	public:
		Student(int,string,float);
		virtual void display();
	protected:
		int num;
		string name;
		float score;		
};
Student::Student(int n,string nam,float s)
{num=n;name=nam;score=s;}
void Student::display()
{
	cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\n\n";
} 
class Graduate:public Student
{
	public:
		Graduate(int,string,float,float);
		void display();
	private:
		float wage;
};
Graduate::Graduate(int n,string nam,float s,float w):Student(n,nam,s),wage(w){}
void Graduate::display()
{
	cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<"\nwage="<<wage<<endl;
}
int main()
{
	Student stud1(1001,"Li",87.5);
	Graduate grad1(2001,"Wang",98.5,1200);
	Student *pt=&stud1;
	pt->display();
	pt=&grad1;
	pt->display();
	return 0;
}
2.静态关联与动态关联

通过对象名调用虚函数,在编译阶段就能确定调用的是那一个类的是静态关联(早期关联),通过基类指针在编译阶段无法确认的则是动态关联(滞后关联)

3.什么情况下应当声明虚函数
(1)使用虚函数的注意事项

只能用virtual声明类的成员函数,并且在该函数被定义为虚函数后,在同一类族的类中就不能定义一个非virtual声明的相同函数。

(2)什么时候使用虚函数

成员函数所在类是否作为基类,成员函数在继承后是否需要改变功能,是否通过基类指针或引用去访问。

有时在定义虚函数时函数体是空的,它的作用只是定义了一个虚函数名,具体功能留给派生类去添加。

使用虚函数系统会有一定的空间开销,当一个类有虚函数时,系统会为其构造一个虚函数表,它是一个指针数组,存放每个虚函数的入口地址。但是其时间开销是很少的。

4.虚析构函数

当基类的析构函数是虚函数,无论指针指的是同一类族的哪个对象,系统都会动态关联调用相应类的析构函数。

在程序中最好把基类的析构函数声明为虚函数,

四、纯虚函数与抽象类

1.没有函数体的纯虚函数
  • 有时会考虑到派生类需要在基类中将某一成员定义为虚函数,在基类中预留一个函数名,具体功能留给派生类根据需要去定义

  • 声明纯虚函数的一般形式

    virtual 函数类型 函数名(参数表列)=0;

    纯虚函数没有函数体,最后的=0不表示函数返回值为0,它只是其形式上的作用

    其派生类中虽然继承了该函数但除非再次用“=0”把它声明为纯虚函数,否则不能称为纯虚函数

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
{
	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:";};
		friend ostream & operator<<(ostream &,const Point &);
	protected:
		float x,y;
};
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<<"]"<<endl;
	return output;
}
class Circle:public Point
{
	public:
		Circle(float x=0,float y=0,float r=0);
		void setRadius(float);
		float getRadius()const;
		virtual float area()const;
		virtual void shapeName() const {cout<<"Circle:";};
		friend ostream & operator<<(ostream &,const Circle&);
	protected:
	    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;}
float Circle::area()const{return 3.14159*radius*radius;}
ostream & operator<<(ostream &output,const Circle&c)
{
	output<<"["<<c.x<<","<<c.y<<"],r="<<c.radius;
	return output;
}
class Cylinder:public Circle
{
	public:
		Cylinder(float x=0,float y=0,float r=0,float h=0);
		void setHeight(float);
		virtual float area() const;
		virtual float volume() const;
		virtual void shapeName() const {cout<<"Cylinder:";};
		friend ostream &operator<<(ostream &,const Cylinder&);
	protected:
		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::area() const{return 2*Circle::area()+2*3.14159*radius*height;}
float Cylinder::volume() const{return Circle::area()*height;}
ostream & operator<<(ostream &output,const Cylinder& cy)
{
	output<<"["<<cy.x<<","<<cy.y<<"],r="<<cy.radius<<",h="<<cy.height;
	return output;
}
int main()
{
	Point point(3.2,4.5);
	Circle circle(2.4,1.2,5.6);
	Cylinder cylinder(3.5,6.4,5.2,10.5);
	point.shapeName();
	cout<<point;
	circle.shapeName();
	cout<<circle<<endl;
	cylinder.shapeName();
	cout<<cylinder<<endl<<endl;
	Shape *pt;
	pt=&point;
	pt->shapeName();
	cout<<"x="<<point.getX()<<",y="<<point.getY()<<"\narea="<<pt->area()<<"\nvolume="<<pt->volume()<<"\n\n";
	pt=&circle;
	pt->shapeName();
	cout<<"x="<<circle.getX()<<",y="<<circle.getY()<<"\narea="<<pt->area()<<"\nvolume="<<pt->volume()<<"\n\n";
	pt=&cylinder;
	pt->shapeName();
	cout<<"x="<<cylinder.getX()<<",y="<<cylinder.getY()<<"\narea="<<pt->area()<<"\nvolume="<<pt->volume()<<"\n\n";
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值