面向对象程序设计-封装性
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
DD( int i1, int i2, int i3, int i4) :Derived1 (i1, i2), Derived2 (i3, i4)
{}
void display ( )
{ cout <<a <<'\n'; }
};
'DD::a' is ambiguous
改进
cout<< Derived1::a <<'\n'; cout<< Derived2::a <<'\n';
父类的私有成员虽然子类不能直接访问,但是确实存 在在子类中。
访问权修饰符只能更严格的限制访问权限,而不能将 父类的访问级别降低
protected的谨慎使用 直接派生类和间接派生类
3 基类成员的访问属性
同名成员
• 派生类和基类的成员名相同 • 类似于全局变量和局部变量的覆盖关系 • 子类成员直接访问,父类成员要使用 类名::成员名 访问 • 如果和全局变量重名,要使用 ::成员 访问全局变量
造函数 – 省略某个父类,表示调用该父类的缺省构造函数
二义性-同名
多重继承的不同父类含有同名成员,名字冲突 为了避免二义性,在访问时需要说明其基类名,由基
类名加作用域分辨符来限定 例子程序
#include <iostream.h>
class X
{
protected:
int a;
public:
class struct union(固定公有)
说明和使用对象
缺省构造函数 带参构造函数 指针
错误检查 系统升级 功能扩展
封装的好处
HasA关系 构造函数
:
对象成员
const对象和const成员
只读对象 只读函数 不允许对Const对象调用非const成员函数 只读对象成员(只能初始化,不能修改) 预定义类型的const成员,也需要使用初始串列
• 访问声明是对其父类的可见性进行调节的机制,用 于私有继承的情况。
访问声明
class Base {
int x; public :
int y,z; int f(int i); } class Derived:private Base { int a; public: Base::y; //调整Base::y的访问属性,与原来基类中的访问属性一 致 int b; void g(); }
(i3, i4),Base(i1){}
注意
虚基类减少了空间开销,但是增加可时间开销 不能提供不同类的多个拷贝 派生类的初始化列中需要对虚基类进行初始化 对虚基类只初始化一次 先调用虚基类的构造函数,再调用非虚类构造函数
基类和派生类的转换
派生类对象 isA 基类对象 可以将一个派生类对象转换为一个基类对象使用 基类对象未必是某个派生类对象 C++不允许将基类对象赋值给派生类对象
赋值兼容规则
虚基类
虚基类只继承一份公共基类 class 派生类名::virtual 访问权修饰符 父类名 上例子改变后就不会出现二义性 class Derived1:public Base class Derived2:public Base DD( int i1, int i2, int i3, int i4) :Derived1 (i1, i2), Derived2
void make(int i)
{a=i; }
};
class Y{
protected:
int a;
public:
void make(int i) {a=i; }
};
class Z:public X, public Y{
public:
int make ( )
{ return X::a*Y::a; }
– class A:public B{ int k; A(int K,int I,int J):B(I,J){k=K;}
}
组合与继承的选择
无论组合还是继承都能把子对象放在新类型中。两者 都使用构造函数的初始化表达式表去构造这些子对象。 现在我们可能会奇怪,这两者之间到底有什么不同? 该如何选择?
#include <iostream.h>
class Base
{
public:
int a;
Base(int i):a(i){}
};
class Derived:public Base
{
public:
int b;
Derived(int i):b(i*15),Base(b){}
};
main()
– 多于一个基类构造函数,中间用“ , ”隔开
组合中的构造函数
– class B; { int i,j; B(int I,int J){i=I;j=J;} }
– class A { int k; B b; A(int K,int I,int J):b(I,J){k=K;} }
继承中的构造函数
– class B { int i,j; B(int I,int J){i=I;j=J;} }
};
void main ( )
{
Z zobj;
zobj.X::make(10);
zobj.Y::make(20);
cout <<zobj.make()<<'\n';
}
200
Press any key to continue
二义性-公共基类
一个类可以多次成为同一个派生类的间接基类,如下:
友元举例
链表设计中,事实上需要两个类型。链表类型和节点 类型。其关系是链表hasA节点。由于链表的特性是链 接,易于插入和删除,但只能顺序检索。所以在链表 中只需要维护头节点信息。
在链表类中,需要使用节点类的指针来指向下一节点, 这就要求在链表类中可以访问节点类的数据成员。
可以将该数据成员设为公有(或者用结构体而不是 class实现)。
第十三讲 封装性
封装性
把描述对象属性的数据和加工处理这些数据的方法一 同放在对象中,并且使得对数据的访问处理只能通过 该对象本身来进行,程序的其他部分不能直接访问或 处理对象的私有数据。
封装就是数据隐藏
C++类和对象
类名 成员说明 访问权限
public private protected 类关键字
{ dl = p2; } };
二义性-公共基类
class Derived2:public Base{
int d2;
public:
Derived2 (int xl, int x2) :Base(xl)
{ d2 =x2; }
};
class DD:Derived1, Derived2 {
public:
静态成员 访问声明
基类成员的访问属性
同名成员 静态成员
• 无论公有还是私有派生,派生类都可以使用基类的静态成员 • 必须使用“类名::静态成员名”显式指定
访问声明
基类成员的访问属性
同名成员 静态成员 访问声明
• 一个类B从其父类A私有派生,父类的所有本来可以 被子类使用的公有或保护类型的成员访问属性都变 成私有。如果类B再派生出类C,则类C不能字节访 问其间接基类的任何非静态成员。
对象数组
缺省构造函数 一个参数的构造函数 两个或者两个以上的构造函数
隐含使用 显式使用
自引用指针this
friend 友元函数 友元类
友元
友元函数
友元函数除了具有访问指定类的私有成员的特权外,其他部分与 普通函数一样。
在A类中声明的友元函数可以访问A类的私有成员。但是友元函数 不是该类的成员函数,因此,没有this指针。
public
protected
private
public
不能在子类中直接访问
public
private
private
protected
private
private
private
private
不能在子类中直接访问
子类不能直接访问父类的私有成员。子类访问父类的 公有成员必须通过父类提供的(公有或者保护类型) 存取函数来实现
class Base
{
int p1,p2;
public :
Base(int i1,int i2){p1=i2;p2=i2;}
};
class Derived:Base
{
int p3;
Base obj;
public:
Derived(int x1,int x2,int x3,int x4,int x5):Base(x1,x2),obj(x3,x4)
类重用和组件重用的基础就是面向对象设计 类重用主要是通过继承和模板实现 组件重用是通过接口实现的,在C++中接口是通过继
承抽象类来实现的
组合对类的重用
– 组合即通过在类A的定义中包含其他类B的对象成员 来对其他类实现的功能进行重用
– 即hasA关系 – 不能进行多态性操作
– 构造函数中,对于组合是在派生类构造函数后加类 B的实例对象,并通过参数对其进行初始化;而继 承是通过构造函数后接类名来构造(因为此时是定 义派生类,没有对象存在)
可以将链表类设为节点类的友元类。 可以为节点类的每一个成员设计存取函数。
第十四讲 继承性
1 什么是继承
继承是一种层次结构。 派生类(学生)。 基类(人)。 派生类拥有基类的全部属性和方法。
继承的好处
软件重用的发展
– 剪切、拷贝、粘贴 – 方法重用(函数重用) – 类重用 – 组件重用 – 服务重用
{ Derived d(10);
cout<<d.b<<" "<<d.a;
}
150 -858993460 Press any key to continue
5 多重继承
语法
– 只有一个直接基类,单继承 java语言只支持单继承
– 派生类可以有多个直接基类,多重继承 – 多重继承中,每个父类名前可以冠以private或者public – 不同类名之间用“,”隔开 – 构造函数的基类初始化串列应该调用该派生类所有父类的构
#include< iostream.h >
class Base{
protected:
int a;
public:
Base (int i)
{a=i; }
};
class Derived1 :public Base{
int dl;
public:
Derived1 (int p1, int p2):Base(p1)
注意
1. 访问属性仅仅调整调整名字的访问属性,不允 许为它说明任何类型。
2. 不允许利用访问声明机制,在派生类中提高和 降低基类成员的可访问性。
3. 对重载函数名的访问声明,将调整基类中所有 数据成员的访问属性。这就意味着基类中访问 属性不同的重载函数名不能通过访问声明调整 其访问属性。
4 派生对象的初始化
组合通常在希望新类内部有已存在类的性能时使用, 而不希望已存在类作为它的接口。这就是说,嵌入一 个计划用于实现新类性能的对象,而新类的用户看到 的是新定义的接口而不是来自老类的接口。为此,在 新类的内部嵌入已存在类的private 对象。有时,允许 类用户直接访问新类的组合是有意义的,这就让成员 对象是public。成员函数隐藏它们自己的实现,所以, 当用户知道我们正在装配一组零件并且使得接口对他 们来说更容易理解时,这样会安全的。
2 C++的继承语法
class EditString:public String { …… …… } 类关键字class 派生类名 :继承符号 继承访问权修饰符 父类名
访问权修饰符
在父类中的访问属性 访问权修饰符 在子类中的访问属性
public
public(缺省) public
protected
{p3=x5;}
}
派生类构造函数的初始化串列中,使用父类名来调用 父类构造函数,使用对象成员名来调用成员对象类型 的构造函数。
组合和继承中的父类或者成员变量的类只要使用其有 参构造函数即可,也需要说明一个空的派生类构造函 数
如果省略父类初始化串,则意味着使用父类的缺省构 造函数
派生类构造函数的执行顺序是,先父类,再对象成员, 最后执行构造函数体的内容
调用友元函数时要在它的实参表中给出要访问的对象。 一个类B的成员函数可以作为类A的友元函数,但在A中说明其友
元函数时,要在函数名前面加上它的类名和作用域分辨符“:”。 如果需要把一个类B的所有成员函数作为另一个类A的友元,则可
以把这个类作为另一个类的友元类 friend class B 友元函数既可以在类的公有段声明,也可以在私有段声明。 友元不具有传递性。 友元不具有交换性。