Effective C++ 2e Item36

【C++】多态(上) 多态 | 虚函数 | 重写 | final、override | 接口继承与实现继承 | 抽象类 若子类定义了一个和父类的虚函数 一模一样的虚函数,那么称子类中的虚函数重写 / 覆盖了父类的虚函数。(拥有相同的名字、返回值、形参列表)重写是针对虚函数的概念。普通函数是没有重写的说法的。 阅读详情

条款36: 区分接口继承和实现继承

(公有)继承的概念看起来很简单,进一步分析,会发现它由两个可分的部分组成:函数接口的继承和函数实现的继承。这两种继承类型的区别和本书简介中所讨论的函数声明和函数定义间的区别是完全一致的。

作为类的设计者,有时希望派生类只继承成员函数的接口(声明);有时希望派生类同时继承函数的接口和实现,但允许派生类改写实现;有时则希望同时继承接口和实现,并且不允许派生类改写任何东西。

为了更好地体会这些选择间的区别,看下面这个类层次结构,它用来表示一个图形程序中的几何形状:

class Shape {
public:
  virtual void draw() const = 0;

  virtual void error(const string& msg);

  int objectID() const;

  ...

};

class Rectangle: public Shape { ... };

class Ellipse: public Shape { ... };

纯虚函数draw使得Shape成为一个抽象类。所以,用户不能创建Shape类的实例,只能创建它的派生类的实例。但是,从Shape(公有)继承而来的所有类都受到Shape的巨大影响,因为:

· 成员函数的接口总会被继承。正如条款35所说明的,公有继承的含义是 "是一个" ,所以对基类成立的所有事实也必须对派生类成立。因此,如果一个函数适用于某个类,也必将适用于它的子类。

Shape类中声明了三个函数。第一个函数,draw,在某一画面上绘制当前对象。第二个函数,error,被其它成员函数调用,用于报告出错信息。第三个函数,objectID,返回当前对象的一个唯一整数标识符(条款17给出了一个怎样使用这种函数的例子)。每个函数以不同的方式声明:draw是一个纯虚函数;error是一个简单的(非纯?)虚函数;objectID是一个非虚函数。这些不同的声明各有什么含义呢?

首先看纯虚函数draw。纯虚函数最显著的特征是:它们必须在继承了它们的任何具体类中重新声明,而且它们在抽象类中往往没有定义。把这两个特征放在一起,就会认识到:

· 定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。

这对Shape::draw函数来说非常有意义,因为,让所有Shape对象都可以被绘制是很合理,但Shape类无法为Shape::draw提供一个合理的缺省实现。例如,绘制椭园的算法就和绘制矩形的算法大不一样。打个比方来说,上面Shape::draw的声明就象是在告诉子类的设计者,"你必须提供一个draw函数,但我不知道你会怎样实现它。"

顺便说一句,为一个纯虚函数提供定义也是可能的。也就是说,你可以为Shape::draw提供实现,C++编译器也不会阻拦,但调用它的唯一方式是通过类名完整地指明是哪个调用:

Shape *ps = new Shape;           // 错误! Shape是抽象的

Shape *ps1 = new Rectangle;      // 正确
ps1->draw();                     // 调用Rectangle::draw

Shape *ps2 = new Ellipse;        // 正确
ps2->draw();                     // 调用Ellipse::draw

ps1->Shape::draw();              // 调用Shape::draw

ps2->Shape::draw();              // 调用Shape::draw

一般来说,除了能让你在鸡尾酒会上给你的程序员同行留下深刻印象外,了解这种用法一般没大的作用。然而,正如后面将看到的,它可以被应用为一种机制,为简单的(非纯)虚函数提供 "比一般做法更安全" 的缺省实现。

有时,声明一个除纯虚函数外什么也不包含的类很有用。这样的类叫协议类(Protocol class),它为派生类仅提供函数接口,完全没有实现。协议类在条款34中介绍过,并将在条款43再次提及。

简单虚函数的情况和纯虚函数有点不一样。照例,派生类继承了函数的接口,但简单虚函数一般还提供了实现,派生类可以选择改写它们或不改写它们。思考片刻就可以认识到:

· 声明简单虚函数的目的在于,使派生类继承函数的接口和缺省实现。

具体到Shape::error,这个接口是在说,每个类必须提供一个出错时可以被调用的函数,但每个类可以按它们认为合适的任何方式处理错误。如果某个类不想做什么特别的事,可以借助于Shape类中提供的缺省出错处理函数。也就是说,Shape::error的声明是在告诉子类的设计者,"你必须支持error函数,但如果你不想写自己的版本,可以借助Shape类中的缺省版本。"

实际上,为简单虚函数同时提供函数声明和缺省实现是很危险的。想知道为什么,看看XYZ航空公司的这个飞机类的层次结构。XYZ公司只有两种飞机,A型和B型,而且两种机型的飞行方式完全一样。所以,XYZ设计了这样的层次结构:

class Airport { ... };      // 表示飞机

class Airplane {
public:
  virtual void fly(const Airport& destination);

  ...

};

void Airplane::fly(const Airport& destination)
{
  飞机飞往某一目的地的缺省代码
}

class ModelA: public Airplane { ... };

class ModelB: public Airplane { ... };

为了表明所有飞机都必须支持fly函数,而且因为不同型号的飞机原则上都需要对fly有不同的实现, 所以Airplane::fly被声明为virtual。但是,为了避免在ModelA类和ModelB类中写重复的代码,缺省的飞行行为是由Airplane::fly函数提供的,ModelA和ModelB继承了这一函数。

这是典型的面向对象设计。两个类享有共同的特征(实现fly的方式),所以这一共同特征被转移到基类,并让这两个类来继承这一特征。这种设计使得共性很清楚,避免了代码重复,将来容易增强功能,并易于长期维护 ---- 所有这一切正是面向对象技术高度吹捧的。XYZ公司真得为此而骄傲。

现在假设XYZ公司发了大财,决定引进一种新型飞机,C型。C型和A型、B型有区别,特别是,飞行方式不一样。

XYZ的程序员在上面的层次结构中为C型增加了一个类,但因为急于使新型飞机投入使用,他们忘了重新定义fly函数:

class ModelC: public Airplane {

  ...                          // 没有声明fly函数
};

然后,在程序中,他们做了类似下面的事:

Airport JFK(...);              // JFK是纽约市的一个机场

Airplane *pa = new ModelC;

...

pa->fly(JFK);                  // 调用Airplane::fly!

这将造成悲剧:竟然试图让ModelC对象如同ModelA或ModelB那样飞行。这种行为可不能换来旅客对你的信任!

这里的问题不在于Airplane::fly具有缺省行为,而在于ModelC可以不用明确地声明就可以继承这一行为。幸运的是,可以很容易做到为子类提供缺省行为、同时只是在子类想要的时候才给它们。窍门在于切断虚函数的接口和它的缺省实现之间的联系。下面是一种方法:

class Airplane {
public:
  virtual void fly(const Airport& destination) = 0;

  ...

protected:
  void defaultFly(const Airport& destination);
};

void Airplane::defaultFly(const Airport& destination)
{
  飞机飞往某一目的地的缺省代码
}

注意Airplane::fly已经变成了纯虚函数,它提供了飞行的接口。缺省实现还是存在于Airplane类中,但现在它是以一个独立函数(defaultFly)的形式存在的。ModelA和ModelB这些类想执行缺省行为的话,只用简单地在它们的fly函数体中对defaultFly进行一个内联调用(关于内联和虚函数间的相互关系,参见条款33):

class ModelA: public Airplane {
public:
  virtual void fly(const Airport& destination)
  { defaultFly(destination); }

  ...

};

class ModelB: public Airplane {
public:
  virtual void fly(const Airport& destination)
  { defaultFly(destination); }

  ...

};

对于ModelC类来说,它不可能无意间继承不正确的fly实现。因为Airplane中的纯虚函数强迫ModelC提供它自己版本的fly。

class ModelC: public Airplane {
public:
  virtual void fly(const Airport& destination);
  ...

};

void ModelC::fly(const Airport& destination)
{
  ModelC飞往某一目的地的代码
}

这个方法不会万无一失(程序员还会因为 "拷贝粘贴" 而出错),但它比最初的设计可靠多了。至于Airplane::defaultFly被声明为protected,是因为它确实只是Airplane及其派生类的实现细节。使用airplane的用户只关心飞机能飞,而不会关心是怎么实现的。

Airplane::defaultFly是一个非虚函数也很重要。因为没有子类会重新定义这个函数,条款37说明了这一事实。如果defaultFly为虚函数,就会又回到这个问题:如果某些子类应该重新定义defaultFly而又忘记去做,那该怎么办?

一些人反对将接口和缺省实现作为单独函数分开,例如上面的fly和defaultFly。他们认为,起码这会污染类的名字空间,因为有这么多相近的函数名称在扩散。然而他们还是赞同接口和缺省实现应该分离。怎么解决这种表面上存在的矛盾呢?可以借助于这一事实:纯虚函数必须在子类中重新声明,但它还是可以在基类中有自己的实现。下面的Airplane正是利用这一点重新定义了一个纯虚函数:

class Airplane {
public:
  virtual void fly(const Airport& destination) = 0;

  ...

};

void Airplane::fly(const Airport& destination)
{
  飞机飞往某一目的地的缺省代码
}

class ModelA: public Airplane {
public:
  virtual void fly(const Airport& destination)
  { Airplane::fly(destination); }

  ...

};

class ModelB: public Airplane {
public:
  virtual void fly(const Airport& destination)
  { Airplane::fly(destination); }

  ...

};

class ModelC: public Airplane {
public:
  virtual void fly(const Airport& destination);

  ...

};

void ModelC::fly(const Airport& destination)
{
  ModelC飞往某一目的地的代码
}

这一设计和前面的几乎一样,只是纯虚函数Airplane::fly的函数体取代了独立函数Airplane::defaultFly。从本质上说,fly已经被分成两个基本部分了。它的声明说明了它的接口(派生类必须使用),而它的定义说明了它的缺省行为(派生类可能会使用,但要明确地请求)。然而,将fly和defaultFly合并后,就不再能够为这两个函数声明不同的保护级别了:本来是protected的代码(在defaultFly中)现在成了public(因为它在fly中)。

最后,来谈谈Shape的非虚函数,objectID。当一个成员函数为非虚函数时,它在派生类中的行为就不应该不同。实际上,非虚成员函数表明了一种特殊性上的不变性,因为它表示的是不会改变的行为 ---- 不管一个派生类有多特殊。所以,

· 声明非虚函数的目的在于,使派生类继承函数的接口和强制性实现。

可以认为,Shape::objectID的声明就是在说,"每个Shape对象有一个函数用来产生对象的标识符,并且对象标识符的产生方式总是一样的。这种方式由Shape::objectID的定义决定,派生类不能改变它。" 因为非虚函数表示一种特殊性上的不变性,所以它决不能在子类中重新定义,关于这一点条款37进行了讨论。

理解了纯虚函数、简单虚函数和非虚函数在声明上的区别,就可以精确地指定你想让派生类继承什么:仅仅是接口,还是接口和一个缺省实现?或者,接口和一个强制实现?因为这些不同类型的声明指的是根本不同的事,所以在声明成员函数时一定要从中慎重选择。只有这样做,才可以避免没经验的程序员常犯的两个错误。

第一个错误是把所有的函数都声明为非虚函数。这就使得派生类没有特殊化的余地;非虚析构函数尤其会出问题(参见条款14)。当然,设计出来的类不准备作为基类使用也是完全合理的(条款M34就给出了一个你会这样做的例子)。这种情况下,专门声明一组非虚成员函数是适当的。但是,把所有的函数都声明为非虚函数,大多数情况下是因为对虚函数和非虚函数之间区别的无知,或者是过分担心虚函数对程序性能的影响(参见条款M24)。而事实上是:几乎任何一个作为基类使用的类都有虚函数(再次参见条款14)。

如果担心虚函数的开销,请允许我介绍80-20定律(参见条款M16)。它指出,在一个典型的程序中,80%的运行时间都花在执行20%的代码上。这条定律很重要,因为它意味着,平均起来,80%的函数调用可以是虚函数,并且它们不会对程序的整体性能带来哪怕一丁点可以觉察到的影响。所以,在担心是否承担得起虚函数的开销之前,不妨将注意力集中在那20%会真正带来影响的代码上。

另一个常见的问题是将所有的函数都声明为虚函数。有时这没错 ---- 比如,协议类(Protocol class)就是证据(参见条款34)。但是,这样做往往表现了类的设计者缺乏表明坚定立场的勇气。一些函数不能在派生类中重定义,只要是这种情况,就要旗帜鲜明地将它声明为非虚函数。不能让你的函数好象可以为任何人做任何事 ---- 只要他们花点时间重新定义所有的函数。记住,如果有一个基类B,一个派生类D,和一个成员函数mf,那么下面每个对mf的调用都必须工作正常:

D *pd = new D;
B *pb = pd;

pb->mf();                    // 通过基类指针调用mf

pd->mf();                    // 通过派生类指针调用mf

有时,必须将mf声明为非虚函数才能保证一切都以你所期望的方式工作(参见条款37)。如果需要特殊性上的不变性,就大胆地说出来吧!

零中频架构实战:用Matlab模拟AD9361收发信号(附完整代码) 本文详细介绍了如何使用Matlab模拟AD9361射频收发器的零中频架构,解决镜像干扰等关键挑战。通过完整的代码示例和系统级建模方法,帮助工程师掌握RFIC设计中的自适应校准算法和性能优化技巧,特别适用于SDR系统开发。 阅读详情

相关推荐

单波束与多波束声呐:从原理到应用场景的全面解析

本文全面解析了单波束与多波束声呐的工作原理、核心特点及应用场景。单波束声呐如精准的狙击手,适合高精度需求;多波束声呐则像高效的散弹枪,适用于快速测绘和大面积覆盖。文章还提供了选型指南和前沿发展趋势,帮助用户根据预算和需求选择最适合的声呐技术。

weixin_30872157的博客 220

接口和继承类的区别

演示一个案例给:USB数组中Phone和相机对象。Phone内还有一个特别的方法或请遍历USB数组,如果是Phone对象,除了调用USB接口定义的方法外,还需要调用phone特有方法call。在前面的usb接口案例,Usb usb,既可以接受手机对象,又可以接受相机对象,就体现了接口多态(接口引用可以指向实现了接口类的对)接口的价值主要在于:设计、设计好各种规范(方法),让其他类去实现这些方法。继承是满足is - a 的关系,而接口只需满足like-a关系。继承的价值主要在于:解决代码的。

qq_45789558的博客 5669

机器学习【学校智慧食堂及其应用】

本文主要介绍机器学习【智慧食堂及其应用】

qq_201729558 2571

继承与接口的区别

抽象类: 抽象类体现了数据抽象的思想,是实现多态的一种机制。它定义了一组抽象的方法,至于这组抽象方法的具体表现形式由派生类来实现。同时抽象类提供了继承的概念,它的出发点就是为了继承,否则它没有存在的任何意义。所以说定义的抽象类一定是用来继承的,同时在一个以抽象类为节点的继承关系等级链中,叶子节点一定是具体的实现类。 在语法方面: 1.由abstract关键词修饰的类称之为抽象类。 2.抽象类中没有实现的方法称之为抽象方法,也需要加关键字abstract。 3.抽象类中也可以没有抽象方法,比如Htt...

M11223344555的博客 2976

STM32CubeMX的正交编码器encoder

由于最近干活遇到需要获取正交编码的功能,所以返回来研究一下STM32CubeMX的编码器功能,之前也更新过STM32的定时器功能,但是因为之前搞平衡车的正交编码器没有搞清楚原理,就直接用了脉冲输入功能草草了事,现在也算是为之前的年轻买单了,不过看到现有的Encoder说明都比较简单,所以就当是为开发者做贡献了,我研究清楚之后来一篇博客。

ASWaterbenben的博客 1万+

微信小程序云开发订单微信支付与小票和标签打印的完整高效流程

本片文章全文12000字,细致讲述从申请账户到小程序注册到打印机的选型最后到实现微信小程序云开发订单支付更新与小票,标签打印完整的高效流程。客户A在我们的点餐平台上点了一杯咖啡,所以客户要在选好后付款,在付款完成后商家的小票打印机和标签打印机打印出本订单的相关信息。

weixin_52312427的博客 3649

继承和接口的区别,抽象类和接口的区别

文章目录1. 继承和接口的区别1.1 面向对象的角度1.2 继承和接口使用上的区别示例2. 抽象类和接口之间的区别2.1 什么是抽象类和接口2.2 特点与区别抽象类的特点接口的特点区别参考链接 主要需要解决的问题: 继承和接口的区别 抽象类和接口之间的区别? 什么时候创建抽象类?什么时候创建接口? 设计框架时该如何选择? 1. 继承和接口的区别 继承不需重载所有方法,接口必须实现所有方法...

怪咖先森的博客 5017

【花雕学编程】Arduino动手做(249)---ESP32+GC9A01之播放GIF的空战锁定动画

摘要: 本实验基于ESP32开发板,驱动1.28寸圆形IPS彩色TFT显示屏(GC9A01驱动,240×240分辨率),通过SPI接口实现GIF动画播放。利用TFT_eSPI和AnimatedGIF库,成功加载并循环播放预置的科幻风格GIF动画(如HUD界面、X翼战机等)。代码实现了GIF解码、逐帧渲染及动态显示功能,通过串口调试监控运行状态。实验验证了该显示屏在动态图像显示中的流畅性,为嵌入式图形应用提供了实用方案,适用于智能穿戴、交互设备等场景。 关键词: ESP32、GC9A01、圆形TFT、GIF播

雕爷学编程 492

自我梳理基础知识--继承与接口的区别

继承。接口。抽象

xingqing_的博客 1325

uniapp - 微信授权登录报错 errMsg“:“login:fail send“ | “code“:-100 | “innerCode“:-6,解决uni-app调用微信登录时没有响应且返回错误

uni-app,微信登录,微信登录报错,微信小程序,支付宝小程序,安卓app,苹果ios,nvue,H5网页网站,uniapp苹果安卓app,微信授权登录,uniAppAPP端微信登录报错,微信确认登录界面后点击登录报错,"errMsg":"login:failsend","errCode":-100,"code":-100,"innerCode":-6,都配置好了还是报错怎么办,uniapp微信授权登录报错,UniApph5对接微信登录出现错误,appid,应用签名,微信登陆,code:-100

🏆 前端领域优质创作者 1万+

ArcMap|时空地理加权回归(GTWR)

ArcGIS的GTWR插件下载地址:https://www.researchgate.net/publication/329518786_GTWR_ADDIN_Valid_till_Dec_31_2022 更详细的操作参考: https://www.bilibili.com/video/BV1fR4y1M7xB?spm_id_from=333.999.0.0 https://blog.youkuaiyun.com/weixin_40008135/article/details/112693520 双击“GTWR_Be

个人学习笔记 1万+

Effective C++ 2e Item44

条款44: 说你想说的;理解你所说的在本章关于 "继承和面向对象设计" 的简介中,我曾强调,理解不同的面向对象构件在C++中的含义十分重要。这和仅仅知道C++语言的规则有很大的不同。例如,C++规则说,如果类D从类B公有继承,从D的指针到B的指针就有一个标准转换;B的公有成员函数将被继承为D的公有成员函数,等等。这些规则都是正确的,但在将设计思想转化为C++的过程中,它们起不到任何作用。相反,

lostmouse的专栏 1148

基于多智能体架构的AI模拟法庭系统:律师案件预演的革命性工具

多智能体系统(Multi-Agent System)是人工智能领域的重要分支,它通过多个自主或半自主的智能体协同工作,模拟复杂的社会交互与决策过程。其核心原理在于分布式问题求解,每个智能体具备感知、推理和行动能力,通过通信与协作实现整体目标。在工程实践中,多智能体架构的价值在于能够模拟真实世界中的信息不对称与策略独立性,从而在复杂决策场景中提供更贴近现实的推演。这一技术正被应用于法律科技领域,通过构建物理隔离的智能体环境,模拟法庭对抗中的信息屏障与策略博弈。例如,在AI模拟法庭系统中,原告、被告、法官等角色

weixin_42561249的博客 393

Effective C++ 2e Item14

条款14: 确定基类有虚析构函数有时,一个类想跟踪它有多少个对象存在。一个简单的方法是创建一个静态类成员来统计对象的个数。这个成员被初始化为0,在构造函数里加1,析构函数里减1。(条款M26里说明了如何把这种方法封装起来以便很容易地添加到任何类中,“my article on counting objects”提供了对这个技术的另外一些改进)设想在一个军事应用程序里,有一个表示敌人目标的类

lostmouse的专栏 976

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Effective C++ 2e Item43

条款43: 明智地使用多继承要看是谁来说,多继承(MI)要么被认为是神来之笔,要么被当成是魔鬼的造物。支持者宣扬说,它是对真实世界问题进行自然模型化所必需的;而批评者争论说,它太慢,难以实现,功能却不比单继承强大。更让人为难的是,面向对象编程语言领域在这个问题上至今仍存在分歧:C++,Eiffel和the Common LISP Object System (CLOS)提供了MI;Smallt

lostmouse的专栏 981

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Effective C++ 2e Item42

条款42: 明智地使用私有继承条款35说明,C++将公有继承视为 "是一个" 的关系。它是通过这个例子来证实的:假如某个类层次结构中,Student类从Person类公有继承,为了使某个函数成功调用,编译器可以在必要时隐式地将Student转换为Person。这个例子很值得再看一遍,只是现在,公有继承换成了私有继承:class Person { ... };class Student:

lostmouse的专栏 930

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Effective C++ 2e Item37

条款37: 决不要重新定义继承而来的非虚函数有两种方法来看待这个问题:理论的方法和实践的方法。让我们先从实践的方法开始。毕竟,理论家一般都很耐心。假设类D公有继承于类B,并且类B中定义了一个公有成员函数mf。mf的参数和返回类型不重要,所以假设都为void。换句话说,我这么写:class B {public:  void mf();  ...};class D: public B

lostmouse的专栏 875

effective c++ item35-39

见https://blog.youkuaiyun.com/weixin_44609676/article/details/130382495可以看到,b和pb调用的是同一个虚方法,但是输出到结果却不一样。因为f是虚函数,在运行时才动态绑定需要执行的函数,但是参数却是静态绑定的,在编译期pb的参数就已经是1了。即使把BC的默认参数都换成1,也不推荐这样做。

weixin_44609676的博客 567

Effective C++ Item 36 绝不重新定义继承而来的 non-virtual 函数

经验:绝对不要重新定义继承而来的 non-virtual 函数 --> Item 7 "为多态基类声明 virtual 析构函数" 是本条款的特例 示例: class B{ public: void mf(); //... }; class D: public B{ public: void mf(); // 遮掩了B::mf,Item 33 名称遮掩规则 } D x; B *pB = &x; D *pD = &x; pB->mf(); // 调用 B::mf pD->mf(); // 调用

880

[翻译] Effective C++, 3rd Edition, 附录 B. 第二和第三版之间的 Item 映射

附录 B. 第二和第三版之间的 Item 映射作者:Scott Meyers译者:fatalerror99 (iTePubs Nirvana)发布:http://blog.youkuaiyun.com/fatalerror99/Effective C++ 的第三版在很多方面与第二版不同,其中最引人注目的是它包含很多新的信息。然而,第二版的大部分内容依然保留在第三版中,虽然经常会改变形式和位置

艺术编程 5819

Effective C++ Item 36 绝不又一次定义继承而来的 non-virtual 函数

本文为senlie原创。转载请保留此地址:http://blog.youkuaiyun.com/zhengsenlie 经验:绝对不要又一次定义继承而来的 non-virtual 函数 --&gt; Item 7 "为多态基类声明 virtual 析构函数" 是本条款的特例 演示样例: class B{ public: void mf(); //... }; class D: p...

weixin_34029680的博客 97

Effective C++ Item 5 了解 C++ 默默编写并调用哪些函数

经验: 如果你自己没声明,编译器会自动声明copy constructor,copy assignment,destructor, 如果你没有声明任何构造函数,编译器会自动声明default constructor

964

Effective C++ Item 34 区分接口继承与实现继承

接口继承和实现继承不同。在 public 继承下, derived classes 总是继承 base class 的接口 class Shape{ public: virtual void draw() const = 0; virtual void error(const std::string &msg); int objectID() const; //... }; class Rectangle: public Shape{...}; class Ellipse: public Sha

861

Effective C++ Item 35 考虑 virtual 函数以外的实现

1.virtual 函数版本 class GameCharacter{ public: virtual int healthValue() const; //返回人物的健康指数, derived classes 可重新定义它 }; 2.使用 non-virtual interface 手法,那是 Template Method 设计模式的一种特殊形式。 让客户通过 public non-virtual 成员函数间接调用 private virtual 函数 class GameCharacter{ pu

978

More Effective C++ Item M32:在未来时态下开发程序

2. 杂项我们现在到了接近结束的部分了,这章讲述的是一些不属于前面任一章节的指导原则。开始两个是关于C++软件开发的,描述的是设计适应变化的系统。面向对象的一个强大之处是支持变化,这两个条款描述具体的步骤来增强你的软件对变化的抵抗能力。然后,我们分析怎么在同一程序中进行C和C++混合编程。这必然导致考虑语言学之外的问题,但C++存在于真实世界中,所以有时我们必须面对这种事情。最后,我将概述C++语

taodm的专栏 1064

Effective C++ Item 5 了解 C++ 默默编写并调用哪些函数

本文为senlie原创,转载请保留此地址:http://blog.youkuaiyun.com/zhengsenlie 经验1: 如果你自己没声明,编译器会自动声明copy constructor,copy assignment,destructor, 如果你没有声明任何构造函数,编译器会自动声明default constructor 示例: 如果你写下

CatEatApple的专栏 536
上一篇: Effective C++ 2e Item35
下一篇: Effective C++ 2e Item37
lostmouse
博客等级 码龄26年 22粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值