类的继承与派生
类的继承与派生
派生类的生成过程,实际上是经历了三个步骤:1、吸收基类成员;2、改造基类成员;3、添加基类成员;
1、吸收基类成员
就是派生类继承从基类过来的所有成员,但是基类的构造函数和析构函数除外;
2、改造基类成员
包含两个方面:
(1)基类成员的访问控制
(2)对基类数据或函数成员的覆盖
就是说如果派生类中声明了一个和基类同名的新成员,(如果声明的是成员函数,则参数列表也要一样,因为参数不同的情况属于重载)
这时候派生类的新成员就覆盖了外层的同名成员;这个时候,在派生类中调用此函数,或者在类外通过对象调用函数则只能访问到派生类中
声明的同名成员,这就是同名覆盖;
3、添加新成员
就是说在派生类中添加一些基类中没有的成员,以实现派生类的新的功能,这也是对派生类的发展;
下面具体介绍一下(1)基类成员的访问控制:
类的继承分为三种:public(公有继承)、protected(保护继承)、private(私有继承);
不同的继承方式,导致派生类对其访问属性也不同,访问属性来自两个方面:1、派生类新增成员对基类继承来的成员的访问;2、派生类外部
通过派生对象对从基类继承来的成员的访问;
一、public(公有继承)
当类的继承方式为public的时候,基类中公有和保护成员的访问属性在派生类中不变,而基类的私有成员不可访问;也就是说,基类中的公有成员和保护成员
被继承到派生类中依然是公有成员和保护成员,派生类的其他成员可以直接访问他们;这时候类外的其他使用者通过类对象只能访问派生类的公有成员;
例子:
class Point //基类(Point)
{
public:
void Initp(float xx = 0,float yy = 0) //基类中用的默认的构造函数,且没有对private:里面的私有变量进行初始化,这里自己声明一个成员函数完成这样的工作;
{
X = xx;
Y = yy;
}
void Move(float xoff,float yoff)
{
X = X + xoff;
Y = Y + yoff;
}
float GetX()
{
return X;
}
float GetY()
{
return Y;
}
private:
float X,Y;
};
class Rectangle : public Point //派生类Rectangle(继承Point,继承方式:公有继承)
{
public:
void InitR(float x,float y , float w, float h) //也是自己定义一个函数初始化成员变量,这里调用基类的公有成员函数
{
Initp(x,y);
W = w;
H = h;
}
float GetW()
{
return W;
}
float GetH()
{
return H;
}
private:
float W,H;
};
int main()
{
Rectangle rect; //定义派生类对象
rect.InitR(2,3,30,50); //调用派生类的公有成员函数
rect.Move(3,2); //调用基类的公有成员函数
cout<<"The data of rect(X,Y,W,H) is:/n";
cout<<rect.GetX()<<","
<<rect.GetY()<<","
<<rect.GetH()<<","
<<rect.GetW()<<endl;
return 0;
}
二、private(私有继承)
当类的继承方式为private的时候,基类中公有和保护成员都已私有成员的身份出现在派生类中,而基类的私有成员不可访问;也就是说,基类中的公有成员和保护成员
被继承到派生类中是私有成员,派生类的其他成员可以直接访问他们;但是类外使用者通过类对象不能访问;
经过私有继承之后,所有基类成员在派生类中不是私有成员就是不可访问的成员,如果进一步派生,基类的所有成员就不能在派生类中访问;因此,私有继承之后,基类的成员
再也无法在以后的派生类中发挥作用,实际上是终止了基类功能的继续派生;
例子:
class Point
{
public:
void Initp(float xx = 0,float yy = 0)
{
X = xx;
Y = yy;
}
void Move(float xoff,float yoff)
{
X = X + xoff;
Y = Y + yoff;
}
float GetX()
{
return X;
}
float GetY()
{
return Y;
}
private:
float X,Y;
};
class Rectangle : private Point
{
public:
void InitR(float x,float y , float w, float h)
{
Initp(x,y); //调用基类的Initp函数,没有命名冲突的话就不用注明域名了;
W = w;
H = h;
}
void Move(float xoff,float yoff)
{
Point::Move(xoff,yoff); //函数调用的时候注明类作用域名,比如要调用基类的Move,为了区别于派生类自己的Move,调用时就加上Point::
}
float GetX()
{
return Point::GetX();
}
float GetY()
{
return Point::GetY();
}
float GetW()
{
return W;
}
float GetH()
{
return H;
}
private:
float W,H;
};
int main()
{
Rectangle rect;
rect.InitR(2,3,30,50);
rect.Move(3,2);
cout<<"The data of rect(X,Y,W,H) is:/n";
cout<<rect.GetX()<<","
<<rect.GetY()<<","
<<rect.GetH()<<","
<<rect.GetW()<<endl;
return 0;
}
解释:因为是私有继承,所以派生类外派生类的对象不能访问从基类继承的成员,所以上面代码中派生类定义了跟基类成员名相同的同名函数。根据同名覆盖原则,会调用派生类的
成员函数;
三、protected(保护继承)
当类的继承方式为protected的时候,基类中公有和保护成员都已保护成员的身份出现在派生类中,而基类的私有成员不可访问;也就是说,基类中的公有成员和保护成员
被继承到派生类中是保护成员,派生类的其他成员可以直接访问他们;但是类外使用者通过类对象不能访问;
保护继承和私有继承在直接派生类中,所有成员的访问属性是一样的;但是如果派生类作为新的基类继续派生时,二者的区别就出现了。假设有一个基类A,派生出类B,B又派生出C,
如果B对A的继承是私有继承,则不管C对B的继承方式是什么,C类的成员和对象都无法访问A类的成员函数;如果B对A的继承是保护继承,那么A的公有和保护成员在B中是保护成员,
C继承B的时候,如果C继承B的方式是公有的,则C间接从A那里继承的成员都是保护的,如果C继承B的方式是保护的,则C间接从A那里继承的成员都是保护的,如果C继承B的方式是私有的,
则C间接从A那里继承的成员都是私有的;因而,C类的成员有可能间接访问从A类那里继承过来的成员;但是C外的C类对象不可能访问A类的成员函数。
---------------------
作者:lovemysea
来源:CSDN
原文:https://blog.csdn.net/lovemysea/article/details/5273930
版权声明:本文为博主原创文章,转载请附上博文链接!