5-1 继承与派生
Problem Description
通过本题目的练习可以掌握继承与派生的概念,派生类的定义和使用方法,其中派生类构造函数的定义是重点。
要求定义一个基类Point,它有两个私有的float型数据成员X,Y;一个构造函数用于对数据成员初始化;有一个成员函数void Move(float xOff, float yOff)实现分别对X,Y值的改变,其中参数xOff和yOff分别代表偏移量。另外两个成员函数GetX() 、GetY()分别返回X和Y的值。
Rectangle类是基类Point的公有派生类。它增加了两个float型的私有数据成员W,H; 增加了两个成员函数float GetH() 、float GetW()分别返回W和H的值;并定义了自己的构造函数,实现对各个数据成员的初始化。
编写主函数main()根据以下的输入输出提示,完成整个程序。
Input
6个float型的数据,分别代表矩形的横坐标X、纵坐标Y、宽度W,高度H、横向偏移量的值、纵向偏移量的值;每个数据之间用一个空格间隔
Output
输出数据共有4个,每个数据之间用一个空格间隔。分别代表偏移以后的矩形的横坐标X、纵坐标Y、宽度W,高度H的值
Example Input
5 6 2 3 1 2
Example Output
6 8 2 3
Hint
输出 -3 4 0 0
Author
黄晶晶
#include <bits/stdc++.h>
using namespace std;
class Point
{
protected:
float X;
float Y;
public:
Point(float XX,float YY)
{
X=XX;
Y=YY;
}
void Move(float xoff, float yoff)
{
X+=xoff;
Y+=yoff;
}
float getx()
{
return X;
}
float gety()
{
return Y;
}
};
class Rectangle:public Point
{
private:
float W;
float H;
public:
Rectangle(float X,float Y,float WW,float HH):Point(X,Y)
{
W=WW;
H=HH;
}
void Change(float WW,float HH)
{
W=WW;
H=HH;
}
float getw()
{
return W;
}
float geth()
{
return H;
}
};
int main()
{
float a1,a2,b1,b2,c1,c2;
cin>>a1>>a2>>b1>>b2>>c1>>c2;
Point p(a1,a2);
p.Move(c1,c2);
Rectangle r(a1,a2,b1,b2);
if(b1<=0)
{
if(b2<=0)
r.Change(0,0);
else
r.Change(0,b2);
cout<<p.getx()<<' '<<p.gety()<<' '<<r.getw()<<' '<<r.geth()<<endl;
}
else
{
cout<<p.getx()<<' '<<p.gety()<<' '<<r.getw()<<' '<<r.geth()<<endl;
}
return 0;
}
简单理解:保持已有类的特性而构造新类的过程称为继承,在已有类的基础上新增自己的特性而产生新类的过程称为派生。
被继承的已有类称为基类(或父类),派生出的新类称为派生类。
总结: 派生类是基类的具体化,而基类则是派生类的抽象。
目的:继承的目的:实现代码重用。
派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造
派生类的声明:
class 派生类名:继承方式 基类名
{
新增加的成员声明;
}
实例:
#include <iostream>
using namespace std;
class Box // 基类
{
private:
int len,wid,hei;
public:
void display( )
{
cout<<"盒子体积="
<<len*wid*hei<<endl;
}
void set( )
{
cin>>len>>wid>>hei;
}
Box(int l=10, int w=10, int h=10)
// 构造函数
{
len = l;
wid = w;
hei = h;
}
};
class colorBox : public Box// 派生类
{
private:
int color;
public:
void dispcolor( )
{
cout<<"盒子的颜色="
<< color << endl;
}
colorBox (int c=0)
{
color = c;
}
};
int main( )
{
colorBox cb1(3); // color初值为3
cb1.dispcolor( );
cb1.set();
cb1.display();
return 0;
}
派生类的构成:
从基类继承的成员,新增加的成员
1.从基类接收(吸收)成员:
派生类把基类的全部成员(不包括构造函数和析构函数)接收过来。
不足之处在于会造成冗余,浪费存储空间和执行效率,
尤其是多次派生时。不要随意地找一个类去派生出某一个子类。
注意:基类的构造函数和析构函数不能继承。
派生类的构造函数:
eg:A为基类,B为派生类
B(int a1,int a2,int b1,int b2):A(a1,a2)
{B1=b1;B2=b2;}
2.调整(改造)从基类接收的成员:
接收基类成员必须照单全收,但编程人员可以对接收过来的成员作一些调整。
如:A.指定不同的继承方式,来改变基类成员在派生类中的访问属性;
B.在派生类中声明一个和基类成员同名的成员,来“遮盖”接收的基类成员。如果想遮盖成员函数,其函数名和参数表必须相同,否则成为重载。
3.在声明派生类时增加新的成员:主要体现子类对基类的扩展。
4.构造派生类的构造函数和析构函数:因为构造和析构函数不能从基类继承
继承方式:
不同继承方式的影响主要体现在:
1.派生类成员对基类成员的访问权限
2.派生类对象对基类成员的访问权限
三种继承方式:
公有继承(public)
私有继承(private)
保护继承(protected)
1.公有继承:
公有继承举例:
#include <iostream>
#include <cmath>
using namespace std;
class Point //基类Point类的定义
{
public: //公有函数成员
void initPoint(float x = 0, float y = 0)
{
this->x = x;
this->y = y;
}
void move(float offX, float offY)
{
x += offX;
y += offY;
}
float getX() const
{
return x;
}
float getY() const
{
return y;
}
private: //私有数据成员
float x, y;
};
class Rectangle: public Point //派生类定义部分
{
public: //新增公有函数成员
void initRectangle(float x, float y, float w, float h)
{
initPoint(x, y); //调用基类公有成员函数
this->w = w;
this->h = h;
}
float getH() const
{
return h;
}
float getW() const
{
return w;
}
private: //新增私有数据成员
float w, h;
};
int main()
{
Rectangle rect; //定义Rectangle类的对象
rect.initRectangle(2, 3, 20, 10);//设置矩形的数据
rect.move(3,2); //移动矩形位置
cout << "The data of rect(x,y,w,h): " << endl;//输出矩形的特征参数
cout << rect.getX() <<", "
<< rect.getY() << ", "
<< rect.getW() << ", "
<< rect.getH() << endl;
return 0;
}
2.私有继承:
访问特性:派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。
通过派生类的对象不能直接访问基类中的任何成员。
私有继承举例:
#include <iostream>
#include <cmath>
using namespace std;
class Rectangle: private Point //派生类定义部分
{
public: //新增公有函数成员
void initRectangle(float x, float y, float w, float h)
{
initPoint(x, y); //调用基类公有成员函数
this->w = w;
this->h = h;
}
void move(float offX, float offY)
{
Point::move(offX, offY);
}
float getX() const
{
return Point::getX();
}
float getY() const
{
return Point::getY();
}
float getH() const
{
return h;
}
float getW() const
{
return w;
}
private: //新增私有数据成员
float w, h;
};
int main()
{
Rectangle rect; //定义Rectangle类的对象
rect.initRectangle(2, 3, 20, 10); //设置矩形的数据
rect.move(3,2); //移动矩形位置
cout << "The data of rect(x,y,w,h): " << endl;
cout << rect.getX() <<", " //输出矩形的特征参数
<< rect.getY() << ", "
<< rect.getW() << ", "
<< rect.getH() << endl;
return 0;
}
3.保护继承:
访问特性:和私有继承一致
protected 成员的特点与作用:
1.对建立其所在类对象的模块来说,它与 private 成员的性质相同。
2.对于其派生类来说,它与 public成员的性质相同。
3.既实现了数据隐藏,又方便继承,实现代码重用。
保护继承举例:
class A
{
protected:
int x;
};
int main()
{
A a;
a.x = 5; //错误
}
class A
{
protected:
int x;
};
class B: public A
{
public:
void function();
};
void B:
function()
{
x = 5; //正确
}
基类中的成员属性 | 公用继承得 来的派生类中(属性不变) | 私有继承得 来的派生类中(变为私有) | 保护继承得 来的派生类中(变为公有) |
私有成员 | 不可访问 | 不可访问 | 不可访问 |
公用成员 | 公用 | 私有 | 保护 |
保护成员 | 保护 | 私有 | 保护 |
三种继承中继承的 基类中的私有成员都不可访问
公用成员:派生类内外都可以访问;
保护成员:派生类内可以访问,派生类外不能访问,其下一级的派生也可以访问;
私有成员:派生类内可以访问,派生类外不能访问,其下一级的派生不可访问;
不可访问的成员:派生类内外都不可访问