C++学习笔记11-面向对象2
1. 仅仅能初始化直接基类
一个类仅仅能初始化自己的直接基类。直接就是在派生列表中指定的类。假设类C 从类B 派生,类B 从类A 派生,则B 是C 的直接基类。尽管每一个C 类对象包括一个A 类部分,但C 的构造函数不能直接初始化A 部分。相反,须要类C 初始化类B,而类B 的构造函数再初始化类A。这一限制的原因是,类B 的作者已经指定了如何构造和初始化B 类型的对象。像类B 的不论什么用户一样,类C 的作者无权改变这个规约。
2. 重构
将Disc_item 加到Item_base 层次是重构(refactoring)的一个样例。重构包含又一次定义类层次,将操作和/或数据从一个类移到还有一个类。为了适应应用程序的须要而又一次设计类以便添加新函数或处理其它改变时,最有可能须要进行重构。
重构常见在面向对象应用程序中很常见。值得注意的是,尽管改变了继承层次,使用Bulk_item 类或Item_base 类的代码不须要改变。然而,对类进行重构,或以随意其它方式改变类,使用这些类的随意代码都必须又一次编译。
3. 尊重基类接口
构造函数仅仅能初始化其直接基类的原因是每一个类都定义了自己的接口。定义Disc_item 时,通过定义它的构造函数指定了如何初始化Disc_item 对象。一旦类定义了自己的接口,与该类对象的全部交互都应该通过该接口,即使对象是派生类对象的一部分也不例外。相同,派生类构造函数不能初始化基类的成员且不应该对基类成员赋值。假设那些成员为public 或protected,派生构造函数能够在构造函数函数体中给基类成员赋值,可是,这样做会违反基类的接口。派生类应通过使用基类构造函数尊重基类的初始化意图,而不是在派生类构造函
 class Derived: public Base {
 public:
 // Base::~Base invoked automatically
数函数体中对这些成员赋值。
4. 派生类析构函数
析构函数的工作与复制构造函数和赋值操作符不同:派生类析构函数不负责撤销基类对象的成员。编译器总是显式调用派生类对象基类部分的析构函数。每一个析构函数仅仅负责清除自己的成员:
5. 虚析构函数
假设删除基类指针,则须要执行基类析构函数并清除基类的成员,假设对象实际是派生类型的,则未定义该行为。要保证执行适当的析构函数,基类中的析构函数必须为虚函数:
 class Item_base {
 public:
 // no work, butvirtual destructor needed
 // if base pointer thatpoints to a derived object is ever deleted
 virtual ~Item_base(){ }
 };
假设析构函数为虚函数,那么通过指针调用时,执行哪个析构函数将因指针所指对象类型的不同而不同:
Item_base *itemP =new Item_base; // same static and dynamic type
delete itemP; // ok:destructor for Item_base called
itemP = newBulk_item; // ok: static and dynamic types differ
delete itemP;<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
6. 作用域与成员函数
在基类和派生类中使用同一名字的成员函数,其行为与数据成员一样:在派生类作用域中派生类成员将屏蔽基类成员。即使函数原型不同,基类成员也会被屏蔽:
 struct Base {
 int memfcn();
 };
 struct Derived : Base{
 int memfcn(int);                  // hides memfcn in the base
 };
 Derived d; Base b;
 b.memfcn();                       // calls Base::memfcn
 d.memfcn(10);                     // calls Derived::memfcn
 d.memfcn();                       // error: memfcn with no arguments is hidden
 d.Base::memfcn();                 // ok: calls Base::memfcn
7. 虚函数与作用域
还记得吗,要获得动态绑定,必须通过基类的引用或指针调用虚成员。当我们这样做时,编译器将在基类中查找函数。假定找到了名字,编译器就检查实參是否与形參匹配。
如今能够理解虚函数为什么必须在基类和派生类中拥有同一原型了。假设基类成员与派生类成员接受的实參不同,就没有办法通过基类类型的引用或指针调用派生类函数。考虑例如以下(人为的)为集合:
class Base {
 public:
 virtual int fcn();
 };
 class D1 : public Base{
 public:
 // hides fcn in thebase; this fcn is not virtual
 int fcn(int);   // parameter list differs from fcn in Base
 // D1 inherits definition of Base::fcn()
 };
 class D2 : public D1{
 public:
 int fcn(int);   // non virtual function hides D1::fcn(int)
 int fcn();      // redefines virtual fcn from Base
 };
D1 中的fcn 版本号没有重定义Base 的虚函数fcn,相反,它屏蔽了基类的fcn。结果D1 有两个名为fcn 的函数:类从Base 继承了一个名为fcn 的虚函数,类又定义了自己的名为fcn 的非虚成员函数,该函数接受一个int 形參。可是,从Base 继承的虚函数不能通过D1 对象(或D1 的引用或指针)调用,由于该函数被fcn(int) 的定义屏蔽了。
类D2 重定义了它继承的两个函数,它重定义了Base 中定义的fcn 的原始版本号并重定义了D1 中定义的非虚版本号
8. 通过基类调用被屏蔽的虚函数
通过基类类型的引用或指针调用函数时,编译器将在基类中查找该函数而忽略派生类:
Base bobj; D1 d1obj;D2 d2obj;
Base *bp1 =&bobj, *bp2 = &d1obj, *bp3 = &d2obj;
bp1->fcn(); // ok:virtual call, will call Base::fcn at run time
bp2->fcn(); // ok:virtual call, will call Base::fcn at run time
bp3->fcn(); // ok:virtual call, will call D2::fcn at run time
9. 名字查找与继承
理解C++ 中继承层次的关键在于理解怎样确定函数调用。确定函数调用遵循下面四个步骤:
1. 首先确定进行函数调用的对象、引用或指针的静态类型。
2. 在该类中查找函数,假设找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。假设不能在类或其相关基类中找到该名字,则调用是错误的。
3. 一旦找到了该名字,就进行常规类型检查查看假设给定找到的定义,该函数调用是否合法。
4. 假定函数调用合法,编译器就生成代码。假设函数是虚函数且通过引用或指针调用,则编译器生成代码以确定依据对象的动态类型执行哪个函数版本号,否则,编译器生成代码直接调用函数。
将派生类对象拷贝到基类对象时,派生类对象将被切掉
10. 句柄类与继承
C++ 中面向对象编程的一个颇具讽刺意味的地方是,不能使用对象支持面向对象编程,相反,必须使用指针或引用。比如,以下的代码段中:
void get_prices(Item_base object,
const Item_base *pointer,
const Item_base &reference)
{
// which version ofnet_price is called is determined at run time
cout <<pointer->net_price(1) << endl;
cout <<reference.net_price(1) << endl; // always invokesItem_base::net_price
cout <<object.net_price(1) << endl;
}
通过pointer 和reference 进行的调用在执行时依据它们所绑定对象的动态类型而确定。
C++学习笔记11-面向对象2的更多相关文章
- Spark学习笔记11面向对象编程
		面向对象编程 11.1 object类 11.1.1定义一个简单的类 11.1.2 field的getter与setter 定义类包含,定义类的field及方法.其格式如下 class Cla ... 
- 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 ... 
- Ext.Net学习笔记11:Ext.Net GridPanel的用法
		Ext.Net学习笔记11:Ext.Net GridPanel的用法 GridPanel是用来显示数据的表格,与ASP.NET中的GridView类似. GridPanel用法 直接看代码: < ... 
- UML和模式应用学习笔记-1(面向对象分析和设计)
		UML和模式应用学习笔记-1(面向对象分析和设计) 而只是对情节的记录:此处的用例场景为:游戏者请求掷骰子.系统展示结果:如果骰子的总点数是7,则游戏者赢得游戏,否则为输 (2)定义领域模型:在领域模 ... 
- SQL反模式学习笔记11  限定列的有效值
		目标:限定列的有效值,将一列的有效字段值约束在一个固定的集合中.类似于数据字典. 反模式:在列定义上指定可选值 1. 对某一列定义一个检查约束项,这个约束不允许往列中插入或者更新任何会导致约束失败的值 ... 
- golang学习笔记11  golang要用jetbrain的golang这个IDE工具开发才好
		golang学习笔记11 golang要用jetbrain的golang这个IDE工具开发才好 jetbrain家的全套ide都很好用,一定要dark背景风格才装B 从File-->s ... 
- Spring MVC 学习笔记11 —— 后端返回json格式数据
		Spring MVC 学习笔记11 -- 后端返回json格式数据 我们常常听说json数据,首先,什么是json数据,总结起来,有以下几点: 1. JSON的全称是"JavaScript ... 
- Lua学习笔记:面向对象
		Lua学习笔记:面向对象 https://blog.csdn.net/liutianshx2012/article/details/41921077 Lua 中只存在表(Table)这么唯一一种数据结 ... 
- Python3+Selenium3+webdriver学习笔记11(cookie处理)
		#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记11(cookie处理)'''from selenium im ... 
- 并发编程学习笔记(11)----FutureTask的使用及实现
		1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ... 
随机推荐
- 详解:(cron , crontab , anacron)
			导读: 人类把时间做了切割,想象一条笔直的线永远向前,本来这条直线上什么都没有,但是人类根据时间的长短(单位)在这条直线上做了密密麻麻的标记(世纪-年-月-日-时-分-秒-纳秒......),通过这样 ... 
- 紫书 例题8-6 UVa 1606(扫描法)
			这道题目用扫描法 扫描法:在枚举的过程中维护一些重要的量, 从而简化计算 这道题用到了极角, 叉积, 高一的我表示一脸懵逼 不过自己去百度了一下好像大概看得懂. 这道题我还有一些疑问, 先这样吧 #i ... 
- C语言中数据类型的字节数
			类型 16位 32 位 64位 char 1 1 1 short int 2 2 2 int 2 4 4 unsigned int 2 4 4 float 4 4 4 double 8 8 8 lon ... 
- SVN学习总结(2)——SVN冲突解决
			在我们用VS进行项目合作开发的过程中,SVN的提交控制是至关重要的,大家不可避免的都遇到过SVN冲突的问题,开发的时候,应该认真学习SVN的知识,减少冲突,集中时间放在开发上. 解决冲突有三种方式: ... 
- 2015 Multi-University Training Contest 3 hdu 5323 Solve this interesting problem
			Solve this interesting problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ... 
- vjudge A - Beautiful numbers
			A - Beautiful numbers Volodya is an odd boy and his taste is strange as well. It seems to him that a ... 
- 【Codeforces】512C Fox and Dinner
			[解析]欧拉筛法,奇偶分析.建二分图,网络流 [Analysis] http://blog.csdn.net/qq574857122/article/details/43453087. 所谓的连通块就 ... 
- BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第1章节--SharePoint 2013 介绍 处理开发者需求
			BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第1章节--SharePoint 2013 介绍 处理开发者需求 SharePoint本质上是一个平台.你 ... 
- POJ - 3321 Apple Tree (线段树 + 建树 + 思维转换)
			id=10486" target="_blank" style="color:blue; text-decoration:none">POJ - ... 
- C++基础之全局变量
			C++的水比較深,之前我一直以为C++的全局变量会像其它语言一样,很easy仅仅要在头文件里,定义一个变量就可以,比方以下的test.h: #ifndef _TEST_H #define _TEST_ ... 
