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的更多相关文章

  1. Spark学习笔记11面向对象编程

    面向对象编程   11.1 object类 11.1.1定义一个简单的类   11.1.2 field的getter与setter 定义类包含,定义类的field及方法.其格式如下 class Cla ...

  2. 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 ...

  3. Ext.Net学习笔记11:Ext.Net GridPanel的用法

    Ext.Net学习笔记11:Ext.Net GridPanel的用法 GridPanel是用来显示数据的表格,与ASP.NET中的GridView类似. GridPanel用法 直接看代码: < ...

  4. UML和模式应用学习笔记-1(面向对象分析和设计)

    UML和模式应用学习笔记-1(面向对象分析和设计) 而只是对情节的记录:此处的用例场景为:游戏者请求掷骰子.系统展示结果:如果骰子的总点数是7,则游戏者赢得游戏,否则为输 (2)定义领域模型:在领域模 ...

  5. SQL反模式学习笔记11 限定列的有效值

    目标:限定列的有效值,将一列的有效字段值约束在一个固定的集合中.类似于数据字典. 反模式:在列定义上指定可选值 1. 对某一列定义一个检查约束项,这个约束不允许往列中插入或者更新任何会导致约束失败的值 ...

  6. golang学习笔记11 golang要用jetbrain的golang这个IDE工具开发才好

    golang学习笔记11   golang要用jetbrain的golang这个IDE工具开发才好  jetbrain家的全套ide都很好用,一定要dark背景风格才装B   从File-->s ...

  7. Spring MVC 学习笔记11 —— 后端返回json格式数据

    Spring MVC 学习笔记11 -- 后端返回json格式数据 我们常常听说json数据,首先,什么是json数据,总结起来,有以下几点: 1. JSON的全称是"JavaScript ...

  8. Lua学习笔记:面向对象

    Lua学习笔记:面向对象 https://blog.csdn.net/liutianshx2012/article/details/41921077 Lua 中只存在表(Table)这么唯一一种数据结 ...

  9. Python3+Selenium3+webdriver学习笔记11(cookie处理)

    #!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记11(cookie处理)'''from selenium im ...

  10. 并发编程学习笔记(11)----FutureTask的使用及实现

    1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ...

随机推荐

  1. 修改maven打包名字

    仅需在pom.xml添加下列配置 build> <finalName>userapi</finalName> </build>

  2. 5、AFM(Attention+FM)-----Attentional Factorization Machines:Learning the Weight of Feature Interactions via Attention Network

    1.摘要: 提出一个Attentional FM,Attention模型+因子分解机,其通过Attention学习到特征交叉的权重.因为很显然不是所有的二阶特征交互的重要性都是一样的,如何通过机器自动 ...

  3. numpy学习笔记 - numpy常用函数、向量化操作及基本数学统计方法

    # -*- coding: utf-8 -*-"""主要记录代码,相关说明采用注释形势,供日常总结.查阅使用,不定时更新.Created on Fri Aug 24 19 ...

  4. [置顶] Docker学习总结(7)——云端基于Docker的微服务与持续交付实践

    本文根据[2016 全球运维大会•深圳站]现场演讲嘉宾分享内容整理而成 讲师简介 易立 毕业于北京大学,获得学士学位和硕士学位:目前负责阿里云容器技术相关的产品的研发工作. 加入阿里之前,曾在IBM中 ...

  5. GET和POST请求的核心区别

    GET请求具有幂等性,而POST请求没有.

  6. 成都磨子桥技工学校 / 2016届练习区 0003:jubeeeeeat

    0003:jubeeeeeat 总时间限制:  1000ms 内存限制:  256000kB 描述 众所周知,LZF很喜欢打一个叫Jubeat的游戏.这是个音乐游戏,游戏界面是4×4的方阵,会根据音乐 ...

  7. Qt之图形(绘制漂亮的圆弧)

    简述 综合前面对二维绘图的介绍,想必我们对一些基本绘图有了深入的了解,下面我们来实现一些漂亮的图形绘制. 简述 圆形 效果 源码 弧形 效果 源码 文本 效果 源码 旋转 效果 源码 圆形 经常地,我 ...

  8. js 动画1

    div速度 运动: 代码例如以下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " ...

  9. linux安装oracleclient

    1.准备好所须要的安装包,http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html这个网 ...

  10. bsp开发之OAL开发

    windows ce 操作系统移植主要包含两个方面:一个是基于cpu级的.还有一个是基于开发板级的.cpu级的主要由微软或者芯片制造商来完毕.开发板级的移植主要是由OEM来完毕的,而OAL的开发正是O ...