您的位置:澳门402永利com > 关于计算机 > 读书笔记

读书笔记

发布时间:2019-09-23 20:45编辑:关于计算机浏览(74)

     

    读书笔记 effective c++ Item 32 确定保障public承接创建“is-a”模型,effectiveis-a

    1. 何为public继承的”is-a”关系

    在C++面向对象法规中最重点的准绳是:public继承意味着“is-a”。记住这些准绳。

    假诺你完成四个类D(derived)public承接自类B(base),你在报告c++编写翻译器(也在告诉代码阅读者),每一个类型D的指标也是二个类型B的靶子,反过来讲是不对的。你正在诉说B比D表示了三个尤其相似的定义,而D比B表现了叁个越来越特殊的概念。你在主张:任何能够运用类型B的地点,也能应用类型D,因为每一种类型D的对象皆以类型B的指标;反过来却极度,也正是足以选择类型D的地点却不得以接纳类型B:D是B,B不是D。

    C++ 会为public承袭强制实行这几个解释。看上边包车型大巴例证:

    1 class Person { ... };
    2 class Student: public Person { ... };
    

    从经常生活中大家知道各类学生都以一位,但并非各类人都以学生。那就是地点的后续种类所主张的。大家愿意对人来讲为真正任何事情——例如一人有出生年月——对学生来讲也是真的。大家不愿意对学员来讲为确实任何事情——比方在三个特定的母校勘和注释册入学——对常常民众以来也是真的。人的定义比学生要进一步一般化;而学员是人的三个一定项目。

    在C++的小圈子内,须求Person类型(也许指向Person的指针恐怕指向Person的引用)参数的别的函数也同样能够应用Student参数(可能指针或援用):

     1 void eat(const Person& p);     // anyone can eat
     2 
     3 void study(const Student& s);            // only students study
     4 
     5 Person p;                            // p is a Person
     6 
     7  
     8 
     9 Student s;       // s is a Student
    10 
    11 eat(p);    // fine, p is a Person
    12 
    13 eat(s);    // fine, s is a Student,
    14 // and a Student is-a Person
    15 
    16 study(s);        // fine
    17 
    18 study(p);        // error! p isn’t a Student
    

     

    那仅对public继承来讲是立见成效的。C++仅仅在Student公共承继自Person的时候,其行为表现才会如上边所描述的。Private承继的意思就完全变了(Item 39),protected承袭是时至明日都让自身深感困惑的事物。

     

     

    2. Public承接也许误导你——例子一,企鹅不会飞

     

    Public承接和”is-a”是等价的听上去差不离,但有时你的直觉会误导你。举例,企鹅是鸟那是个实际,鸟能飞也是事实。借使尝试用C++表示,将会生出下边的代码: 

     1 class Bird {
     2 public:
     3 virtual void fly();            // birds can fly
     4 
     5 ...                                   
     6 
     7 };
     8 class Penguin: public Bird {    // penguins are birds
     9 
    10 ...                                   
    11 
    12 
    13 };
    

     

    咱俩溘然陷入了劳动,因为这些两次三番种类申明了企鹅会飞,我们清楚那不是真的。发生了哪些?

    1. 何为public继承的”is-a”关系

    在C++面向对象法规中最重视的法规是:public承接意味着“is-a”。记住这些法则。

    万一你完成三个类D(derived)public承袭自类B(base),你在告知c++编写翻译器(也在告知代码阅读者),各样类型D的靶子也是三个类型B的对象,反过来讲是不对的。你正在诉说B比D表示了二个越发相似的概念,而D比B表现了叁个特别特殊的定义。你在主持:任何能够运用类型B的地方,也能应用类型D,因为每一种类型D的靶子都以类型B的靶子;反过来却有失水准,也正是足以使用类型D的地点却不能应用类型B:D是B,B不是D。

    C++ 会为public承袭强制实行那么些解释。看上边包车型地铁事例:

    1 class Person { ... };
    2 class Student: public Person { ... };
    

    从平常生活中大家掌握种种学员都以一位,但实际不是种种人都以学员。那便是地点的接续种类所主见的。大家盼望对人来讲为真正任何事情——比如一个人有出生年月——对学员来讲也是真的。我们不指望对学员来讲为真正任何职业——举例在一个一定的这个学院勘和注释册入学——对经常众人来讲也是真的。人的概念比学生要尤其一般化;而学生是人的贰个一定项目。

    在C++的圈子内,供给Person类型(或然指向Person的指针也许指向Person的引用)参数的任何函数也长久以来能够利用Student参数(也许指针或援用):

     1 void eat(const Person& p);     // anyone can eat
     2 
     3 void study(const Student& s);            // only students study
     4 
     5 Person p;                            // p is a Person
     6 
     7  
     8 
     9 Student s;       // s is a Student
    10 
    11 eat(p);    // fine, p is a Person
    12 
    13 eat(s);    // fine, s is a Student,
    14 // and a Student is-a Person
    15 
    16 study(s);        // fine
    17 
    18 study(p);        // error! p isn’t a Student
    

     

    那仅对public传承来说是一蹴而就的。C++仅仅在Student公共承接自Person的时候,其行为表现才会如上面所汇报的。Private承继的意思就全盘变了(Item 39),protected承继是时至前几日都让自家备感纳闷的事物。

     

    2.1 管理上述难点的主意一——越发正确的建立模型,不定义fly

    在这种情景下,大家是一种不纯粹语言——马耳他语——的被害人。当我们说鸟能飞,大家并不曾说有着的鸟都能飞,经常状态下唯有有其一力量的才行。假如越来越规范一些,咱们能够辨识出有一点点不能飞的鸟的品种,就足以行使如下的接轨连串,它越来越好的里丑捧心了切实:

     1 class Bird {
     2 ...                                       // no fly function is declared
     3 
     4 };
     5 class FlyingBird: public Bird {
     6 public:
     7 virtual void fly();
     8 ...
     9 };
    10 class Penguin: public Bird {
    11 ...                                       // no fly function is declared
    12 
    13 
    14 };
    

     

    其接二连三续种类比原本的规划尤为忠于现实。 

    至于那几个家畜的事体还未曾完,因为对此某些软件系统的话,无需对能飞和不能够飞的鸟进行区分。即便你的运用越来越关怀鸟嘴和鸟的翎翅而对会不会飞漠不关怀,最开头的七个类的接轨类别就够用了。那影响了一个简易的真情:从未二个能够的布置适用于全数软件最佳的宏图取决于供给系统去做什么样,无论是将来照旧现在。假诺你的使用尚未与飞相关的学问,何况长久也不会有,对能还是不可能飞不做区分恐怕是三个宏观而且有效的计划性决策。事实上,能够区分它们的安顿恐怕更可取,因为您品尝为其建立模型的这种不一致有一天大概会从社会风气上未有。

    2. Public继承或许误导你——例子一,企鹅不会飞

     

    Public承袭和”is-a”是等价的听上去轻易,但神蹟你的直觉会误导你。举例,企鹅是鸟那是个真相,鸟能飞也是实际意况。假如尝试用C++表示,将会产生上面包车型客车代码: 

     1 class Bird {
     2 public:
     3 virtual void fly();            // birds can fly
     4 
     5 ...                                   
     6 
     7 };
     8 class Penguin: public Bird {    // penguins are birds
     9 
    10 ...                                   
    11 
    12 
    13 };
    

     

    大家赫然陷入了麻烦,因为这些三番两次类别表明了企鹅会飞,大家精晓这不是真的。发生了什么样?

    2.2 管理上述难点的形式二——产生运行时不当

    有别的一个学派来管理作者上边所陈诉的“全体的鸟能飞,企鹅是鸟,企鹅不能飞”难题。便是重复为企鹅定义fly函数,不过让其发出运营时不当:

     

    1 void error(const std::string& msg); // defined elsewhere
    2 class Penguin: public Bird {
    3 public:
    4 virtual void fly() { error("Attempt to make a penguin fly!"); }
    5 ...
    6 };
    7 
    8  
    

     

    上边所说的大概会和您想的分裂,能够分辨它们很关键。上边的代码并不曾说,“企鹅不能够飞。”而是说,“企鹅能飞,然而它们一旦尝试那样做会是四个荒谬”。

     

    2.1 处理上述问题的方法一——特别正确的建立模型,不定义fly

    在这种意况下,大家是一种不精确语言——韩文——的遇害者。当大家说鸟能飞,我们并不曾说富有的鸟都能飞,平时意况下独有有其一力量的才行。假诺进一步标准一些,我们能够辨识出有一点不可能飞的鸟的类型,就能够选择如下的承继体系,它更加好的模仿了切实:

     1 class Bird {
     2 ...                                       // no fly function is declared
     3 
     4 };
     5 class FlyingBird: public Bird {
     6 public:
     7 virtual void fly();
     8 ...
     9 };
    10 class Penguin: public Bird {
    11 ...                                       // no fly function is declared
    12 
    13 
    14 };
    

     

    本条连续种类比原本的设计更是忠于现实。 

    有关那个家畜的政工还尚无完,因为对于部分软件系统来讲,没有须求对能飞和不可能飞的鸟举办区分。假使您的利用越发关切鸟嘴和鸟的膀子而对会不会飞漠不爱慕,最先导的三个类的接续种类就丰富了。那反应了贰个简短的实际境况:一贯不一个不错的计划适用于具备软件最棒的安排性取决于须要系统去做什么样,无论是未来照旧未来。假设你的施用尚未与飞相关的学问,并且永世也不会有,对能还是不能够飞不做区分大概是贰个两全而且有效的安排性决策。事实上,能够区分它们的准备恐怕更可取,因为您品尝为其建立模型的这种差距有一天或然会从社会风气上未有。

    2.3 区分二者的不一样——编译期错误和平运动转时不当

    你哪些手艺揭发它们的例外?从破绽非常多被检测出来的大运点看,“企鹅无法飞“这些禁令能够被编译器强制实践,不过倘诺违反“企鹅尝试飞行是一个不当”那些准则只可以够在运维时亦可被检查评定出来。

     

    为了表示“企鹅不能够飞”那么些界定,你要保管对Penguin对象的话未有这么的函数被定义:

    1 class Bird {
    2 ...                                     // no fly function is declared
    3 
    4 };
    5 class Penguin: public Bird {
    6 ...                                     // no fly function is declared
    7 
    8 
    9 };
    

     

    倘使你品尝让企鹅飞起来,编写翻译器会呵斥你的行事:

    1 Penguin p;
    2 
    3 p.fly();                                      // error!
    4 
    5  
    

     

    那同发生运维时不当的办法有着不小的例外。如若您利用运行时报错的主意,编写翻译器对p.fly的调用不会说一句话。Item 18解说了好的接口应该在编写翻译期就能够拦截无效代码,所以比起只好在运行时能力侦测出来错误的安排,你应有尤为喜爱在编写翻译期就能够拒绝企鹅飞翔的统一计划。

     

    2.2 管理上述难点的点子二——发生运维时不当

    有另外三个学派来管理本身上边所陈说的“全数的鸟能飞,企鹅是鸟,企鹅无法飞”难点。即是重复为企鹅定义fly函数,可是让其发出运营时不当:

     

    1 void error(const std::string& msg); // defined elsewhere
    2 class Penguin: public Bird {
    3 public:
    4 virtual void fly() { error("Attempt to make a penguin fly!"); }
    5 ...
    6 };
    7 
    8  
    

     

    地点所说的可能会和你想的不均等,能够辨识它们很关键。上面的代码并未说,“企鹅无法飞。”而是说,“企鹅能飞,可是它们一旦尝试那样做会是三个荒谬”。

     

    3. Public承接恐怕误导你——例子二,矩形和长方形

     

    唯恐你会做出妥胁是因为您对鸟类学知识的贫乏,不过你能够借助你对起来几何的相通,对啊?矩形和星型会有多复杂呢?

     

    今昔答应那么些大致的主题素材:长方形类应该public承接自星型类么?

     

    你会说“当然应该!每种人都明白星型是三个矩形,反之却不树立。”再真可是了,至少是在这个学院内部。不过本人觉着大家已经不在学校里面了。

    思量上边包车型大巴代码:

     1 class Rectangle {
     2 public:
     3   virtual void setHeight(int newHeight);
     4   virtual void setWidth(int newWidth);
     5 
     6 virtual int height() const;        // return current values
     7 
     8 virtual int width() const;       
     9 
    10 ...                                            
    11 
    12 };                                           
    13 
    14  
    15 
    16 void makeBigger(Rectangle& r)   // function to increase r’s area
    17 
    18 {                                                  
    19 
    20 int oldHeight = r.height();           
    21 
    22  
    23 
    24 r.setWidth(r.width() + 10);   // add 10 to r’s width
    25 
    26 assert(r.height() == oldHeight);         // assert that r’s
    27 
    28  
    29 
    30 }                                                             // height is unchanged
    

     

    很掌握,断言永恒不会出错,makeBigger只会修改r的增长幅度。中度永世不会被改造。

     

    于今思量上面包车型地铁代码,使用public继承,能够使纺锤形被看成矩形管理:

     1 class Square: public Rectangle { ... };
     2 
     3 Square s;
     4 
     5 ...
     6 
     7 assert(s.width() == s.height());
     8 
     9 // this must be true for all squares
    10 
    11 makeBigger(s);
    12 
    13 // by inheritance, s is-a Rectangle,
    14 
    15 
    16 // so we can increase its area
    17 assert(s.width() == s.height()); // this must still be true
    18 // for all squares
    

     

    很清楚的是第贰个断言恒久不可能战败。依照定义,四个长方形的宽度和冲天应该同样。

    而是未来大家有二个标题。大家怎么本事使上边包车型地铁断言一致呢?

    • 在调用makeBigger在此以前,s的莫斯中国科学技术大学学和增幅是大同小异的;
    • 在makeBigger里面,s的增进率被改动了,不过中度却未有;
    • makeBigger重临之后,s的惊人和宽窄如故一直以来。(注意s被按援引传递给makeBigger,所以makeBigger修改了s本人,并非s的正片)

     

    招待来到public承接的杰出世界,你在其余领域学习而来的直觉(包罗数学),使用起来或者和你想要的差异样。上边例子的着力的困难在于适用于矩形的东西(宽度独立于高度被涂改)却不适用江小鱼方形(长度宽度必需一律)。可是public承接主见适用于基类对象的其余事物一样适用于派生类对象。对于星型和长方形的情况(还会有Item3第88中学涉及到的sets和lists的例证),这么些主张不再适用,所以选用public承接来为其建立模型是不得法的。编写翻译器大概会令你如此做,但是正如大家恰赏心悦目到的,大家不能确认保证代码的一坐一起是合情合理的。那也是种种技术员必须求学到的:编码编写翻译通过了不代表它能源办公室事。

     

    2.3 区分二者的例外——编写翻译期错误和平运动行时不当

    您什么手艺揭破它们的不等?从错误被检查实验出来的时光点看,“企鹅不可能飞“那个禁令能够被编写翻译器强制实行,不过假若违反“企鹅尝试飞行是二个谬误”这些准则只好在运转时能够被检查评定出来。

     

    为了表示“企鹅不能够飞”这一个范围,你要有限支撑对Penguin对象的话未有那样的函数被定义:

    1 class Bird {
    2 ...                                     // no fly function is declared
    3 
    4 };
    5 class Penguin: public Bird {
    6 ...                                     // no fly function is declared
    7 
    8 
    9 };
    

     

    假使你品尝让企鹅飞起来,编写翻译器会指斥你的一颦一笑:

    1 Penguin p;
    2 
    3 p.fly();                                      // error!
    4 
    5  
    

     

    那同爆发运转时不当的秘诀有着异常的大的不及。假若您使用运转时报错的措施,编写翻译器对p.fly的调用不会说一句话。Item 18解说了好的接口应该在编写翻译期就可见阻止无效代码,所以比起只好在运作时手艺侦测出来错误的统一策动,你应当更为喜欢在编写翻译期就能够拒绝企鹅飞翔的宏图。

     

    4. 行使public承接要有新的洞察力 

    最近几年里使用面向对象设计的时候软件上的直觉会让您没戏,不要烦躁。这一个知识照旧有价值,今后您的设计兵工厂中又增加了可供替换的持续,你不可能不用新的洞察力来扩充你的直觉,辅导你方便的使用持续。当部分人向您来得长达几页的函数时,你会回忆企鹅承接自鸟类大概纺锤形承接自圆锥形这个让你感到有趣的业务。它大概是拍卖事务的不利方法,只是或不是特意像。

     

    3. Public承袭恐怕误导你——例子二,矩形和圆锥形

     

    恐怕你会做出妥洽是因为您对鸟类学知识的不足,不过你能够依赖你对最先几何的明白,对吧?矩形和长方形会有多复杂呢?

     

    目前答应那个大约的主题材料:星型类应该public承接自圆柱形类么?

     

    您会说“当然应该!各样人都理解纺锤形是一个矩形,反之却不树立。”再真可是了,至少是在母校内部。不过小编感觉大家早就不在高校内部了。

    考虑下边包车型大巴代码:

     1 class Rectangle {
     2 public:
     3   virtual void setHeight(int newHeight);
     4   virtual void setWidth(int newWidth);
     5 
     6 virtual int height() const;        // return current values
     7 
     8 virtual int width() const;       
     9 
    10 ...                                            
    11 
    12 };                                           
    13 
    14  
    15 
    16 void makeBigger(Rectangle& r)   // function to increase r’s area
    17 
    18 {                                                  
    19 
    20 int oldHeight = r.height();           
    21 
    22  
    23 
    24 r.setWidth(r.width() + 10);   // add 10 to r’s width
    25 
    26 assert(r.height() == oldHeight);         // assert that r’s
    27 
    28  
    29 
    30 }                                                             // height is unchanged
    

     

    很通晓,断言恒久不会出错,makeBigger只会修改r的增长幅度。中度永恒不会被修改。

     

    现行反革命虚构上面包车型地铁代码,使用public承袭,能够使正方形被当做矩形管理:

     1 class Square: public Rectangle { ... };
     2 
     3 Square s;
     4 
     5 ...
     6 
     7 assert(s.width() == s.height());
     8 
     9 // this must be true for all squares
    10 
    11 makeBigger(s);
    12 
    13 // by inheritance, s is-a Rectangle,
    14 
    15 
    16 // so we can increase its area
    17 assert(s.width() == s.height()); // this must still be true
    18 // for all squares
    

     

    很明亮的是第三个断言长久无法失利。依照定义,叁个正方形的宽度和中度应该一样。

    但是现在我们有一个难点。大家怎么技能使下边包车型地铁断言一致呢?

    • 在调用makeBigger在此以前,s的可观和宽窄是一模一样的;
    • 在makeBigger里面,s的拉长率被改成了,不过中度却绝非;
    • makeBigger重回之后,s的可观和宽窄仍旧同样。(注意s被按援引传递给makeBigger,所以makeBigger修改了s本人,而不是s的正片)

     

    应接来到public承接的大好世界,你在任何世界学习而来的直觉(包含数学),使用起来恐怕和您想要的不均等。下面例子的主干的难关在于适用于矩形的东西(宽度独立于中度被改造)却不适用徐婧方形(长宽必需一律)。可是public承接主张适用于基类对象的其余东西一律适用于派生类对象。对于纺锤形和长方形的意况(还会有Item3第88中学涉及到的sets和lists的例子),那一个主见不再适用,所以采取public承接来为其建立模型是不得法的。编写翻译器也许会让你如此做,可是比很大家恰美观到的,大家不能保证代码的一言一动是没有错的。这也是种种程序猿必供给学到的:编码编写翻译通过了不表示它能做事。

     

    5. 任何两系列关系 

    “is-a”关系不是存在类之间的唯有的关乎。别的七个常见的类之间的涉及是“has-a”和“is-implemented-in-terms-of”。这么些关系在Item38和Item39中被介绍。C++设计出现谬误不要不广泛,因为别的重大的类关系有不小希望不科学的被建立模型为”is-a”,所以你应当保障能清楚那个涉及里面包车型大巴区分,何况精晓C++中什么最佳的培养它们。

    4. 施用public承接要有新的洞察力 

    近几来里应用面向对象设计的时候软件上的直觉会让您没戏,不要烦躁。这个知识照旧有价值,未来您的设计兵工厂中又增加了可供替换的接续,你无法不用新的洞察力来扩充你的直觉,教导你方便的选取持续。当部分人向你显得长达几页的函数时,你会记念企鹅传承自鸟类恐怕长方形承继自纺锤形这一个令你以为到有意思的业务。它或许是处监护人务的不利方法,只是否特地像。

     

    6. 总结

    Public承继意味着“is-a”.应用于base类的每件东西必需也能使用于派生类,因为种种派生类对象是三个基类对象。

    5. 任何两系列关系 

    “is-a”关系不是存在类之间的独有的涉及。其它七个常见的类之间的涉嫌是“has-a”和“is-implemented-in-terms-of”。那些关系在Item38和Item39中被介绍。C++设计出现错误不要不布满,因为别的关键的类关系有望不科学的被建立模型为”is-a”,所以你应该保险能清楚那几个涉嫌里面包车型大巴区分,并且知道C++中哪些最棒的培养它们。

    6. 总结

    Public承接意味着“is-a”.应用于base类的每件东西必须也能利用于派生类,因为每一个派生类对象是一个基类对象。

    effective c++ Item 32 确定保证public承袭建构“is-a”模型,effectiveis-a 1. 何为public承接的is-a关系 在C++面向对象法规中最重点的轨道是:pu...

    本文由澳门402永利com发布于关于计算机,转载请注明出处:读书笔记

    关键词:

上一篇:没有了

下一篇:判断元素是否存在,41判断元素存在