长沙网站建设论坛,全网营销推广,长尾关键词在网站优化中起的作用有哪些,济南街道办网站建设派生类继承了基类的全部数据成员和除了构造函数和析构函数之外的全部函数成员#xff0c;但是这些成员的访问属性在派生的过程中是可以调整的。从基类继承的成员#xff0c;其访问属性由继承方式控制。
基类的成员有public#xff08;公有#xff09;、protected#xff…派生类继承了基类的全部数据成员和除了构造函数和析构函数之外的全部函数成员但是这些成员的访问属性在派生的过程中是可以调整的。从基类继承的成员其访问属性由继承方式控制。
基类的成员有public公有、protected保护和private私有三种访问属性。基类的自身成员可以对基类中任何一个其他成员进行访问但是通过基类的对象只能访问该类的公有成员。
类的继承方式有public公有继承、protected保护继承和private私有继承三种。不同的继承方式导致原来具有不同访问属性的基类成员在派生类中的访问属性也有所不同。这里说的访问来自两个方面一是派生类中新增成员访问从基类继承的成员二是在派生类外部通过派生类对象访问从基类继承的成员。
1.公有继承
当类的继承方式为公有继承时基类的公有成员和保护成员的访问属性在派生类中不变而基类的私有成员不可以直接访问。 也就是说基类的公有成员和保护成员被继承到派生类中访问属性不变仍作为派生类的公有成员和保护成员派生类的其他成员可以直接访问它们。在类族之外只能通过派生类的对象访问从基类继承的公有成员而无论是派生类的成员还是派生类的对象都无法直接访问基类的私有成员。
【例1】Point类公有继承 将从Point类派生出新的Rectangle矩形类。矩形是由一个点加上长、宽构成。矩形的点具备了Point类的全部特征同时矩形自身也有一些特点就需要在继承Point类的同时添加新的成员。
程序的头文件部分如下 Point.h文件
#pragma once
#ifndef _POINT_H
#define _POINT_H
class Point//基类Point的定义
{
public://公有函数成员void initpoint(float x 0, float y 0){this-x x;this-y y;}void move(float ox, float oy){x ox;y oy;}float getX()const{return x;}float getY()const{return y;}
private://私有数据成员float x, y;
};#endifRectangle.h文件:
#pragma once
#ifndef _RECTANGLE_H
#define _RECTANGLE_H
#includePoint.h
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;
};#endif这里首先定义了基类Point。派生类Rectangle继承了Point类的全部成员隐含的默认构造函数和析构函数除外因此在派生类中实际拥有的成员就是从基类继承过来的成员和派生类新定义成员的总和。继承方式为公有继承这时基类中的公有成员在派生类中的访问属性保持原样派生类的成员函数及对象可以访问到基类的公有成员例如在派生类Rectangle的函数成员initRectangle中直接调用基类的函数initpoint,但是无法访问基类的私有成员例如xy。基类原有的外部接口例如getX()和getY()函数变成了派生类外部接口的一部分。当然派生类自己新增的成员之间都是可以互相访问的。
Rectangle类继承了Point类的成员也就实现了代重用同时通过新增成员加入了自身的独有特征达到了程序的扩充。
程序的主函数部分如下
#includeiostream
using namespace std;
#includeRectangle.h
int main()
{Rectangle r;//定义Rectangle类的对象r.initRectangle(2, 3, 20, 10);//设置矩形的数据r.move(3, 2);//移动矩形的位置cout 这个矩形的数据x,y,w,h: endl;cout r.getX() , r.getY() , r.getW() , r.getH() endl;//输出矩形的特征参数return 0;
}运行结果 分析 主函数中首先声明了一个派生类对象r对象生成时调用了系统所产生的默认构造函数这个函数的功能是什么都不做。任何通过派生类的对象r访问了派生类的公有函数initRectangle也访问了派生类从基类继承来的公有函数和move()、getX()和getY()。这样我们看到从一个基类以公有继承的方式产生了派生类之后在派生类的成员函数中以及通过派生类的对象如何访问从基类继承的公有成员。
2.私有继承
当类的继承方式为私有继承时基类中的公有成员和保护成员都以私有成员身份出现在派生类中而基类的私有成员在派生类中不可以直接访问。 也就是说基类的公有成员和保护成员被继承后作为派生类的私有成员派生类的其他成员可以直接访问它们但是在类族外部通过派生类的对象无法直接访问它们。无论是派生类成员还是通过派生类的对象都无法直接访问从基类继承的私有成员。
经过私有继承后所有基类的成员都成为了派生类的私有成员或不可直接访问的成员如果进一步派生的话基类的全部成员就无法在新的派生类中被直接访问。因此私有继承之后基类的成员再也无法在以后的派生类中直接发挥作用实际上相当于中止了基类功能的继续派生出于这种原因一般情况私有继承使用较少。
【例2】Point类私有继承
程序类的定义部分如下
Point.h文件
#pragma once
#ifndef _POINT_H
#define _POINT_H
class Point//基类Point的定义
{
public://公有函数成员void initpoint(float x 0, float y 0){this-x x;this-y y;}void move(float ox, float oy){x ox;y oy;}float getX()const{return x;}float getY()const{return y;}
private://私有数据成员float x, y;
};#endifRectangle.h文件
#ifndef _RECTANGLE_H
#define _RECTANGLE_H
#includePoint.h
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 ox, float oy){Point::move(ox, oy);}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;
};
#endif派生类Rectangle继承了Point类的成员因此在派生类中实际拥有的成员就是从基类继承的成员与派生类新成员的总和。继承方式是私有继承这时基类中的公有和保护成员在派生类中都以私有成员的身份出现。派生类成员的成员函数及对象无法访问基类的私有成员例如基类的xy。派生类的成员仍然可以访问到从基类继承过来的公有和保护成员例如在派生类函数成员initRectangle中直接调用基类的函数initpoint但是在类的外部通过派生类的对象无法访问到基类的任何成员基类原有的外部接口例如getX()和getY()函数被派生类封装和隐藏起来。当然派生类新增的成员之间仍然可以自由地相互访问。
在私有继承的情况下为了保证基类的一部分外部接口能够在派生类中也存在就必须在派生类中重新声明同名的成员。这里在派生类Rectangle中重新声明了movegetXgetY等函数利用派生类对基类成员的访问能力把基类的原有成员函数的功能照搬过来。这种在派生类中重新声明的成员函数具有比基类同名成员函数更小的作用域因此在调用时根据同名隐藏的原则自然会使用派生类的函数。
程序的主函数部分
#includeRectangle.h
int main()
{Rectangle r;//定义Rectangle类的对象r.initRectangle(2, 3, 20, 10);//设置矩形的数据r.move(3, 2);//移动矩形的位置cout 这个矩形的数据x,y,w,h: endl;cout r.getX() , r.getY() , r.getW() , r.getH() endl;//输出矩形的特征参数return 0;
}运行结果 分析
主函数部分和公有继承的主函数部分的代码完全相同但是执行过程不同。本例中的Rectangle类对象r调用的函数都是派生类自身的公有成员因为私有继承它不可能访问到任何一个基类的成员。和例1的Point的公有继承相比较本例对程序修改的只是派生类的内容基类和主函数部分没有改变。Rectangle类的外部接口不变内部成员的实现做了改造没有影响到程序的其他部分这正是面向对象程序设计重用和扩充的一个实际体现。
3.保护继承
保护继承中基类的公有成员和保护成员都以保护成员的身份出现在派生类中而基类的私有成员不可以直接访问。 这样派生类的其他成员就可以直接访问从基类继承来的公有和保护成员但在类的外部通过派生类的对象无法直接访问它们。无论时派生类成员还是派生类对象都无法直接访问基类的私有成员。
比较私有继承和保护继承可以看出实际上在直接派生类中所有成员的访问属性都是完全相同的。但是如果派生类作为新的基类继续派生时二者就有区别了。假设Rectangle类以私有继承的方式继承了Point类之后Rectangle类又派生出Square类那么Square类的成员和对象都不能访问间接从Point来中继承来的成员。如果Rectangle类是以保护继承的方式继承了Point类那么Point类中的公有和保护成员在Retangle类中都是保护成员Retangle类再派生出Square类之后Point类中的公有和保护成员被Square类间接继承后有可能是保护或者私有根据从Rectangle到Square的派生方式不同而不同。因而Square类的成员有可能可以访问间接从Point类中继承来的成员。
从继承的访问规则可以看到类中保护成员的特征。如果Point类中含有保护成员对于建立Point类对象的模块来讲保护成员和该类的私有成员一样是不可以访问的。如果Point类派生除了Rectangle类则对于Rectangle类来讲保护成员和私有成员具有相同的访问特性。换句话来说就是Point类中的保护成员有可能被它的派生类访问但是决不可能被其他外部使用者程序中的普通函数、与Point类平行的其他类访问。
这样如果合理地利用保护成员就可以在类的复杂层关系中在共享与成员隐藏之间找到一个平衡点既能实现成员隐蔽又能方便继承实现代码的高效重用和扩充。
假定某一个类A有保护数据成员x我们来讨论x的访问特征。
类A定义为
class A
{
protected://保护数据成员int x;
};如果主函数为
int main()
{A a;a.x5;//错误
}程序在编译阶段就会出错错误原因是在建立A类对象的模块——主函数中试图访问A类的保护成员这是不允许的因为该成员的访问规则和A类的私有成员是相同的。这就说明在建立A类对象a的模块中无法访问A类的保护成员在这种情况下保护成员和私有成员一样得到了很好的隐蔽。
如果类A以公有继承的方式派生产生了B类则在B类中A类的保护成员和该类的公有成员一样可以访问。例如
class A
{
protected:int x;
};
class B:public A
{
public:void fun();
};void B::fun()
{x5;
}在派生类B的成员函数fun内部是完全可以访问基类的保护成员的。
【注意】如果B是A的派生类B的成员函数只能通过B的对象访问A中定义的protected成员而不能通过A的对象访问A的protected成员。