C++学习笔记10-面向对象
1. 面向对象的程序设计是基于三个基本概念:数据抽象、继承和动态绑定。
在C++ 在,凭借一流的数据抽象,随着一类从一个类派生还继承:派生类的成员继承基类。决定是使用基类中定义的函数还是派生类中定义的函数。在C++ 中,多态性仅用于通过继承而相关联的类型的引用或指针。
2. 继承
通过继承我们能够定义这种类,它们对类型之间的关系建模,共享公共的东西,只特化本质上不同的东西。派生类(derivedclass)能够继承基类(baseclass)定义的成员,派生类能够无须改变而使用那些与派生类型详细特性不相关的操作,派生类能够重定义那些与派生类型相关的成员函数。将函数特化。考虑派生类型的特性。最后,除了从基类继承的成员之外。派生类还能够定义很多其它的成员。
在C++ 中,基类必须指出希望派生类重写哪些函数。定义为 virtual 的函数是基类期待派生类又一次定义的,基类希望派生类继承的函数不能定义为虚函数。
3. 动态绑定
动态绑定我们能够编敲代码使用继承层次中随意类型的对象,无须关心对象的详细类型。使用这些类的程序无须区分函数是在基类还是在派生类中定义的。
在C++ 中。通过基类的引用(或指针)调用虚函数时,发生动态绑定。
引用(或指针)既能够指向基类对象也能够指向派生类对象,这一事实是动态绑定的关键。
用引用(或指针)调用的虚函数在执行时确定。被调用的函数是引用(或指针)所指对象的实际类型所定义的。
4. 基类成员函数
保留字 virtual 的目的是启用动态绑定。成员默觉得非虚函数,对非虚函数的调用在编译时确定。
为了指明函数为虚函数,在其返回类型前面加上保留字virtual。除了构造函数之外,随意非static 成员函数都能够是虚函数。
保留字仅仅在类内部的成员函数声明中出现。不能用在类定义体外部出现的函数定义上。
5. 訪问控制和继承
在基类中,public和private 标号具有普通含义:用户代码能够訪问类的public 成员而不能訪问private 成员。private成员仅仅能由基类的成员和友元訪问。派生类对基类的public 和private 成员的訪问权限与程序中随意其它部分一样:它能够訪问public 成员而不能訪问private 成员。
protected 成员能够被派生类对象訪问但不能被该类型的普通用户訪问。能够觉得protected 訪问标号是private
和public 的混合:
- 像private 成员一样。protected成员不能被类的用户訪问。
- 像public 成员一样,protected成员可被该类的派生类訪问。
- 此外。protected还有还有一重要性质:
- 派生类仅仅能通过派生类对象訪问其基类的protected 成员,派生类对其基类类型对象的protected 成员没有特殊訪问权限。
6. 派生类
为了定义派生类,使用类派生列表指定基类。
类派生列表指定了一个或多个基类,具有例如以下形式:
class classname:access-label base-class
这里access-label 是public、protected或private。base-class是已定义的类的名字。
类派生列表能够指定多个基类。
继承单个基类是为常见。
• 假设是公用继承。基类成员保持自己的訪问级别:基类的public 成员为派生类的public 成员。基类的protected 成员为派生类的protected 成员。
• 假设是受保护继承。基类的public 和protected 成员在派生类中为 protected 成员。
• 假设是私有继承,基类的的全部成员在派生类中为private 成员。
比如,考虑以下的继承层次:
class Base {
public:
void basemem(); //public member
protected:
int i; // protectedmember
// ...
};
struct Public_derived: public Base {
int use_base() {return i; } // ok: derived classes can access i
// ...
};
structPrivate_derived : private Base {
int use_base() {return i; } // ok: derived classes can access i
};
不管派生列表中是什么訪问标号,全部继承 Base 的类对Base 中的成员具有同样的訪问。派生訪问标号将控制派生类的用户对从Base 继承而来的成员的訪问:
Base b;
Public_derived d1;
Private_derived d2;
b.basemem(); // ok: basemem is public
d1.basemem(); // ok: basemem is public in the derived class
d2.basemem(); // error: basemem is private in thederived class
// 派生訪问标号还控制来自非直接派生类的訪问:
struct Derived_fromPrivate : public Private_derived {
// error: Base::i isprivate in Private_derived
int use_base() {return i; }
};
structDerived_from_Public : public Public_derived {
// ok: Base::iremains protected in Public_derived
int use_base() {return i; }
};
7. 用作基类的类必须是已定义的
已定义的类才干够用作基类。假设已经声明了Item_base 类,但未定义它,则不能用Item_base 作基类:
class Item_base; //declared but not defined
// error: Item_base mustbe defined
class Bulk_item :public Item_base { ... };
这一限制的原因应该非常easy明确:每一个派生类包括而且能够訪问其基类的成员。为了使用这些成员,派生类必须知道它们是什么。
这一规则暗示着不可能从类自身派生出一个类。
8. 不论什么能够在基类对象上运行的操作也能够通过派生类对象使用。
由于能够使用基类类型的指针或引用来引用派生类型对象,所以,使用基类类型的引用或指针时,不知道指针或引用所绑定的对象的类型:基类类型的引用或指针能够引用基类类型对象。也能够引用派生类型对象。不管实际对象具有哪种类型,编译器都将它当作基类类型对象。
将派生类对象当作基类对象是安全的,由于每一个派生类对象都拥有基类子对象。
并且,派生类继承基类的操作
基类类型引用和指针的关键点在于静态类型(在编译时可知的引用类型或指针类型)和动态类型(指针或引用所绑定的对象的类型这是仅在执行时可知的)可能不同。
9. C++ 中的多态性
引用和指针的静态类型与动态类型能够不同,这是C++ 用以支持多态性的基石。
通过基类引用或指针调用基类中定义的函数时。我们并不知道运行函数的对象的确切类型,运行函数的对象可能是基类类型的。也可能是派生类型的。
假设调用非虚函数。则不管实际对象是什么类型,都执行基类类型所定义的函数。假设调用虚函数,则直到执行时才干确定调用哪个函数,执行的虚函数是引用所绑定的或指针所指向的对象所属类型定义的版本号。 从编写代码的角度看我们无需操心。仅仅要正确地设计和实现了类。不管实际对象是基类类型或派生类型,操作都将完毕正确的工作。 还有一方面,对象是非多态的——对象类型已知且不变。
对象的动态类型总是与静态类型同样,这一点与引用或指针相反。执行的函数(虚函数或非虚函数)是由对象的类型定义的。
仅仅有通过引用或指针调用,虚函数才在执行时确定。仅仅有在这些情况下。直到执行时才知道对象的动态类型。
在编译时确定非 virtual 调用
10. 覆盖虚函数机制
在某些情况下,希望覆盖虚函数机制并强制函数调用使用虚函数的特定版本号,这里能够使用作用域操作符:
Item_base *baseP =&derived;
// calls version from the base class regardless of the dynamic type of baseP
double d =baseP->Item_base::net_price(42);
11. 为什么会希望覆盖虚函数机制?
最常见的理由是为了派生类虚函数调用基类中的版本号。
在这样的情况下,基类版本号能够完毕继承层次中全部类型的公共任务,而每一个派生类型仅仅加入自己的特殊工作。
派生类虚函数调用基类版本号时。必须显式使用作用域操作符。假设派生类函数忽略了这样做,则函数调用会在执行时确定并且将是一个自身调用,从而导致无穷递归。
12. 继承与组合
继承层次的设计本身是个复杂的主题,已超出本书的范围。可是,有一个重要的设计指南很基础。每一个程序猿都应该熟悉它。
定义一个类作为还有一个类的公用派生类时,派生类应反映与基类的“是一种(IsA)”关系。
在书店样例中,基类表示按规定价格销售的书的概念,Bulk_item是一种书,但具有不同的定价策略。
类型之间还有一种常见的关系是称为“有一个(HasA)”的关系。书店样例中的类具有价格和ISBN。
通过“有一个”关系而相关的类型暗含有成员关系,因此,书店样例中的类由表示价格和ISBN 的成员组成。
13. 去除个别成员
假设进行private 或protected 继承,则基类成员的訪问级别在派生类中比在基类中更受限:
class Base {
public:
std::size_t size()const { return n; }
protected:
std::size_t n;
};
class Derived :private Base { . . . };
派生类能够恢复继承成员的訪问级别,但不能使訪问级别比基类中原来指定的更严格或更宽松。
在这一继承层次中,size在Base 中为public,但在Derived 中为private。为了使size 在Derived 中成为public。可以在Derived 的public部分添加一个using 声明。例如以下这样改变Derived 的定义。可以使 size 成员可以被用户訪问,并使n 可以被从Derived 派生的类訪问:
class Derived :private Base {
public:
// maintain access levels for members related to the size of the object
using Base::size;
protected:
using Base::n;
// ...
};
14. 默认继承保护级别
struct 和class 保留字定义的类具有不同的默认訪问级别。相同,默认继承訪问级别依据使用哪个保留字定义派生类也不相同。使用class 保留字定义的派生默认具有private 继承,而用struct 保留字定义的类默认具有public 继承:
class Base { /* ...*/ };
struct D1 : Base { /*... */ }; // public inheritance bydefault
class D2 : Base { /*... */ }; // private inheritance bydefault
15. 友元关系与继承
友元关系不能继承。
基类的友元对派生类的成员没有特殊訪问权限。
假设基类被授予友元关系。则仅仅有基类具有特殊訪问权限。该基类的派生类不能訪问授予友元关系的类。
每一个类控制对自己的成员的友元关系:
class Base {
friend class Frnd;
protected:
int i;
};
// Frnd has no accessto members in D1
class D1 : publicBase {
protected:
int j;
};
class Frnd {
public:
int mem(Base b) {return b.i; } // ok: Frnd is friend to Base
int mem(D1 d) {return d.i; } // error: friendship doesn't inherit
};
// D2 has no accessto members in Base
class D2 : publicFrnd {
public:
int mem(Base b) {return b.i; } // error: friendship doesn't inherit
};
16. 继承与静态成员
不管从基类派生出多少个派生类,每一个static 成员仅仅有一个实例。
static 成员遵循常规訪问控制:假设成员在基类中为private。则派生类不能訪问它。假定能够訪问成员。则既能够通过基类訪问static 成员,也能够通过派生类訪问static 成员。
一般而言,既能够使用作用域操作符也能够使用点或箭头成员訪问操作符。
struct Base {
static voidstatmem(); // public by default
};
struct Derived : Base{
void f(constDerived&);
};
void Derived::f(constDerived &derived_obj)
{
Base::statmem(); // ok: Base defines statmem
Derived::statmem(); // ok: Derived in herits statmem
// ok: derivedobjects can be used to access static from base
derived_obj.statmem(); // accessed through Derived object
statmem(); // accessed through this class
C++学习笔记10-面向对象的更多相关文章
- python学习笔记(10):面向对象
一.类和实例 1.类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 2.对象:通过类定义的数据结构实例.对象包括两个数据成员( ...
- 《C++ Primer Plus》学习笔记10
<C++ Primer Plus>学习笔记10 <<<<<<<<<<<<<<<<<&l ...
- Android:日常学习笔记(10)———使用LitePal操作数据库
Android:日常学习笔记(10)———使用LitePal操作数据库 引入LitePal 什么是LitePal LitePal是一款开源的Android数据库框架,采用了对象关系映射(ORM)的模式 ...
- ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则
ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...
- thinkphp学习笔记10—看不懂的路由规则
原文:thinkphp学习笔记10-看不懂的路由规则 路由这部分貌似在实际工作中没有怎么设计过,只是在用默认的设置,在手册里面看到部分,艰涩难懂. 1.路由定义 要使用路由功能需要支持PATH_INF ...
- UML和模式应用学习笔记-1(面向对象分析和设计)
UML和模式应用学习笔记-1(面向对象分析和设计) 而只是对情节的记录:此处的用例场景为:游戏者请求掷骰子.系统展示结果:如果骰子的总点数是7,则游戏者赢得游戏,否则为输 (2)定义领域模型:在领域模 ...
- SQL反模式学习笔记10 取整错误
目标:使用小数取代整数 反模式:使用Float类型 根据IEEE754标识,float类型使用二进制格式编码实数数据. 缺点:(1)舍入的必要性: 并不是所有的十进制中描述的信息都能使用二进制存储,处 ...
- golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息
golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...
- Spring MVC 学习笔记10 —— 实现简单的用户管理(4.3)用户登录显示全局异常信息
</pre>Spring MVC 学习笔记10 -- 实现简单的用户管理(4.3)用户登录--显示全局异常信息<p></p><p></p>& ...
- Hadoop学习笔记(10) ——搭建源码学习环境
Hadoop学习笔记(10) ——搭建源码学习环境 上一章中,我们对整个hadoop的目录及源码目录有了一个初步的了解,接下来计划深入学习一下这头神象作品了.但是看代码用什么,难不成gedit?,单步 ...
随机推荐
- Lisp学习:这是本质与应用?
The Common Lisp Programming Language "The programming language of choice for those who set out ...
- Android Gradle Plugin指南(六)——高级构建定制
原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Advanced-Build-Customization ...
- 安装windows7导致Ubuntu启动项消失的问题的解决
系统原来是Ubuntu14,前两天安装win7后,启动直接是win7.也就是Ubuntu的启动项消失了. 在windows下尝试非常多方法,都以失败告终,最后选择Ubuntu下boot-repair软 ...
- EasyUI - 后台管理系统 - 登陆模块
效果: --- --- Html代码: <div id="login"> <p>账户:<input type="text" id= ...
- GnuWin,包括FLEX BISON GREP
https://sourceforge.net/projects/gnuwin32/files/?source=navbar
- ASM - 条件判断
技术交流,DH讲解. 正式之前,我们看看寄存器和CPU的标志位: OD中的截图,下方的CPAZSTDO就是标志位. Delphi的FPU窗口,右边一列就是标志位.为什么要给大家看标志位呢?因为ASM中 ...
- SPSS Modeler数据挖掘项目实战(数据挖掘、建模技术)
SPSS Modeler是业界极为著名的数据挖掘软件,其前身为SPSS Clementine.SPSS Modeler内置丰富的数据挖掘模型,以其强大的挖掘功能和友好的操作习惯,深受用户的喜爱和好评, ...
- hdu 2871 Memory Control(伸展树splay tree)
hdu 2871 Memory Control 题意:就是对一个区间的四种操作,NEW x,占据最左边的连续的x个单元,Free x 把x单元所占的连续区间清空 , Get x 把第x次占据的区间输出 ...
- VxWorks6.6 pcPentium BSP 使用说明(二):创建启动盘
本篇介绍从Solaris.Linux.Windows或VxWorks创建VxWorks启动盘的方法. 从Solaris或Linux创建启动盘 使用Solaris或Linux自带的工具/usr/bin/ ...
- Appium Server 传递的基本参数
Appium Server 传递的基本参数 官方列表 Appium server capabilities Capability Description Values automationName ...