【effective c++】繼承與面向對象設計

1.確定你的public繼承塑造出is-a關系

public繼承意味著is-a.適用于base classes身上的每一件事情一定也適用于derived classes身上,因為每一個derived classes對象也都是一個base class對象,反過來不成立。

2.避免隱藏繼承而來的名稱

c++名稱查找不考慮類型,只考慮名稱。

class Base
{
private:int x;
public:virtual void mf1() = 0;virtual void mf1(int){}virtual void mf2(){}void mf3(){}void mf3(double){}
};
class Derived :public Base
{
public:virtual void mf1(){}void mf3(){}void mf4(){}
};
/*
base class內所有名為mf1和mf3的函數都被derived class內的mf1和mf3函數遮掩掉
函數隱藏只與函數名稱有關,與函數的參數類型、是否virtual無關,注意此處是靜態綁定
若通過指針或引用來調用虛函數,此時是動態綁定,不會發生函數隱藏
*/ int main() {Derived d;int x = 1;d.mf1();//ok//d.mf1(x);//falsed.mf2();//okd.mf3();//ok//d.mf3(x);//false system("pause");return 0; }
class Base
{
private:int x;
public:virtual void mf1() = 0;virtual void mf1(int){}virtual void mf2(){}void mf3(){}void mf3(double){}
};class Derived :public Base
{
public:using Base::mf1;using Base::mf3;virtual void mf1(){}void mf3(){}void mf4(){}
};/*
如果你繼承base class并且base class中有重載函數,而你又希望在派生類中重新定義其中一部分,那么你必須為那些
原本會被隱藏的每個名稱引入一個using聲明式,否則某些你希望繼承的名稱會被隱藏。using聲明式會令繼承而來的基類中某
給定名稱之所有同名函數在derived class中都可見
*/ int main() {Derived d;int x = 1;d.mf1();//okd.mf1(x);//okd.mf2();//okd.mf3();//okd.mf3(x);//ok system("pause");return 0; }

3.區分接口繼承和實現繼承

  • 聲明一個pure virtual函數的目的是為了讓derived classes只繼承函數接口

通常純虛函數沒有定義,但是可以為純虛函數提供定義,調用它的唯一途徑是調用時明確指出其class名稱

class Shape
{
public:virtual void draw() const = 0{}virtual void error(const string& msg);int objectID() const;
};class Rectangle:public Shape
{
public:virtual void draw() const{}
};class Ellipse:public Shape
{
public:virtual void draw() const {}
};int main()
{//Shape *ps = new Shape;//error 抽象類不能生成實例Shape *ps1 = new Rectangle;ps1->draw();Shape *ps2 = new Ellipse;ps2->draw();ps1->Shape::draw();ps2->Shape::draw();system("pause");return 0;
}
  • 聲明impure virtual函數的目的,是讓derived class繼承該函數的接口和缺省實現

如果有的派生類只想繼承接口但忘記重新定義該虛函數,這樣一來就會使用基類缺省實現,出錯:將接口和缺省實現分開,派生類如果想使用缺省實現,需要去顯式調用

方案一:將接口定義為純虛函數,缺省實現定義為non-virtual函數,派生類若想使用缺省實現,需要在繼承而來的純虛函數中調用該non-virtual函數,派生類若只想繼承接口,此時不會忘記重新定義該虛函數了,因為不重新定義的話就是抽象類,無法實例化

方案二:純虛函數必須在derived class中重新定義,但基類中也可以為純虛函數提供定義,該定義作為缺省實現。派生類若想使用缺省實現,需要在在繼承而來的純虛函數中通過基類名來顯式調用上述函數定義

  • 聲明non-virtual函數的目的是為了令derived class繼承函數的接口及一份強制性實現

4.考慮virtual函數以外的其他選擇

  • NVI手法:令用戶通過public non-virtual成員函數間接調用private virtual函數
  • 由Function Pointer實現strategy模式

運用函數指針(作為類的成員變量)替換virtual函數,優點是每個對象可各自擁有自己的對應函數及可在運行期改變該函數,缺點是可能會降低類的封裝性

  • 由tr1::function完成strategy模式
  • 古典的strategy模式

5.絕不重新定義繼承而來的non-virtual函數(設計理念)

6.絕不重新定義繼承而來的缺省參數值

虛函數是動態綁定的,而缺省參數值是靜態綁定的。

class Shape
{
public:enum ShapeColor{Red,Green,Blue};virtual void draw(ShapeColor color = Red) const = 0;
};class Circle :public Shape
{
public:/*當用戶以對象調用此函數,一定要指定參數值。因為靜態綁定下這個函數并不從其基類繼承缺省參數值。但若以指針或引用調用此函數,可以不指定參數值,因為動態綁定下這個函數會從其基類繼承缺省參數值*/virtual void draw(ShapeColor color) const;
};

7.通過復合composition塑造出has-a或"根據某物實現出"

復合:某種類型的對象內含別的類型的對象,復合意味著has-a或is-implemented-in-terms-of

8.明智地使用private繼承

  • 如果class之間的繼承關系是private,編譯器不會自動將一個derived class對象轉換為一個base class對象(將派生類實參傳遞給基類形參,編譯出錯)
  • 由private base class繼承而來的所有成員,在derived class中都會變成private屬性,縱使它們在base class中原本是protected或public屬性,即派生類對象不能調用基類方法

private繼承意味著implemented-in-terms-of,private繼承純粹只是一種實現技術。

9.明智地使用多重繼承

未完待續

轉載于:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/5819125.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/256497.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/256497.shtml
英文地址,請注明出處:http://en.pswp.cn/news/256497.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android Camera HAL淺析

1、Camera成像原理介紹 Camera工作流程圖 Camera的成像原理可以簡單概括如下: 景物(SCENE)通過鏡頭(LENS)生成的光學圖像投射到圖像傳感器(Sensor)表面上,然后轉為電信號,經過A/D(模數轉換)轉換…

win10 下pycharm+anaconda 編譯生成pyd文件

由于生產部署的問題,需要把用python寫的深度學習代碼編譯為可被調用的文件。上網搜索了下,暫時了解到win10下pyd文件比較流行。下面是直接引用某位博主的結論,個人感覺總結的很好。其中Cython庫將已有的Python代碼轉化為C語言的代碼&#xff…

ANSYS——初學路徑之路徑的定義、作用以及ansys路徑模塊GUI的操作解釋

目錄 一、路徑的定義 二、路徑的作用 三、路徑GUI相關操作面板解釋 1、路徑的定義

JVM(4)之 使用MAT排查堆溢出

為什么80%的碼農都做不了架構師?>>> 接下來講解如何設置以及當發生堆溢出的時候怎么排查問題。先看一小段代碼: ??代碼中使用了一個無限循環來為list添加對象,如果采用默認的堆大小的話可能要等待好久才能出現堆溢出的錯誤&a…

caffe 中的一些參數介紹

轉自:http://blog.csdn.net/cyh_24/article/details/51537709 solver.prototxt net: "models/bvlc_alexnet/train_val.prototxt" test_iter: 1000 # test_interval: 1000 # base_lr: 0.01 # 開始的學習率 lr_policy: "step" # 學習率的…

ANSYS——相同模型不同創建方式的同載荷同約束下的比較

目錄 1、問題描述: 2、相同部分: 3、梁單元創建(BEAM) 4、實體單元創建

python 制作二進制文件數據集(bin)

為了方便進行深度學習的程序調用與實現,需要將excel的數據文件轉換為二進制文件。好處就是接口統一,讀寫速度快,節約空間。 一、調用庫 使用xlrd讀入execel表格,經過處理后轉換為對應的dataframe結構,再使用pickle庫…

ConcurrentDictionary的ToDictionary

如果Value是引用&#xff0c;那么在使用Value.Clear()的時候。會清空Value的所有元素&#xff0c;但是不會改變Value的引用 private static void Main(){try{var concurrentDictionary new ConcurrentDictionary<string, List<int>>();concurrentDictionary.TryAd…

遠程連接mysql數據庫注意點記錄

一、如何新建獨立帳號并設置權限 這里我使用Navicat作為我的數據庫管理工具&#xff0c;打開Navicat。 選擇“用戶”--“新建用戶” 輸入用戶名、主機、密碼&#xff0c;需要注意的是&#xff0c;主機那不是寫“localhost”&#xff0c;而是寫“%” 然后可以設置“服務器權限”…

【域控管理】父域的搭建

從這篇博文開始&#xff0c;所有的域控系統都是在虛擬機中創建的。 在VM里安裝Windows Server 2008 R2的方法就不多說了&#xff0c;無腦式安裝&#xff0c;略過不提。 進到系統桌面&#xff0c;打開本地連接&#xff0c;設置網卡的IP地址&#xff0c;如下圖&#xff1a; 注意&…

ANSYS——網格劃分的不同方法以及GUI模塊的操作(自由網格、映射網格、掃掠、拖拉)

目錄 一、GUI操作模塊的解釋 二、不同的網格劃分方法和網格類型

tensorflow2 tensorboard可視化使用

tensorflow2自帶tensorboard&#xff0c;所以不必再自行安裝tensorboard。 一、使用環境 win10 x64&#xff1b; anaconda3tensorflow2&#xff08;cpu版本&#xff09; 二、使用 1.在模型訓練之前插入以下代碼 log_dir os.path.join(logs) #win10下的bug&#xff0c; if…

oracle字符亂碼的解決方法

原因分析&#xff1a; 客戶端字符集就是為了讓數據庫知道我們傳遞過去的字符是屬于哪種字符集&#xff0c;以便于Oracle在存儲字符時進行相應的編碼映射&#xff08;查看客戶端字符集通過查找注冊表中的NLS_LANG鍵&#xff09;。在客戶端查詢數據庫時顯示字符的時候我們使用的是…

[]End of 2017OI

今年大概到此為止了&#xff0c;現在這個算是做一個簡短的階段性總結吧 今年打的第一場大概是省賽&#xff0c;當時整個人處于&#xff08;迷茫&#xff0c;不知道選物理還是選信息備戰中考持續摸魚OI頹廢&#xff09;的狀態&#xff0c;KMP都不會導致簽到題都沒有分&#xff0…

Javascript閉包——懂不懂由你,反正我是懂了

摘要&#xff1a;“如果你不能向一個六歲的孩子解釋清楚&#xff0c;那么其實你自己根本就沒弄懂。”好吧&#xff0c;我試著向一個27歲的朋友就是JS閉包(JavaScript closure)卻徹底失敗了。越來越覺得國內沒有教書育人的氛圍&#xff0c;為了弄懂JS的閉包&#xff0c;我使出了…

ANSYS——命令流學習(材料屬性設置、建模的命令流)

目錄 ANSYS基本關鍵字 命令流的整體結構、每個模塊的標識 !文件說明段/BATCH

IOS用CGContextRef畫各種圖形(文字、圓、直線、弧線、矩形、扇形、橢圓、三角形、圓角矩形、貝塞爾曲線、圖片)...

首先了解一下CGContextRef: An opaque type that represents a Quartz 2D drawing environment. Graphics Context是圖形上下文,可以將其理解為一塊畫布,我們可以在上面進行繪畫操作,繪制完成后,將畫布放到我們的view中顯示即可,view看作是一個畫框. 自己學習時實現的demo&…

eclipse maven jetty插件方式啟動項目

2019獨角獸企業重金招聘Python工程師標準>>> 1. 2.點擊run即可啟動項目 參考:maven命令具體含義請自行百度.例子:maven clean的作用 / maven djetty 轉載于:https://my.oschina.net/u/3146772/blog/1576710

AWS S3 Windows系統下的文件夾上傳基于python

AWS S3 上傳文件&#xff0c;基于cmd命令行發現無法上傳文件夾&#xff0c;只能上傳單個文件&#xff0c;不知道是我能力不行還是什么原因&#xff0c;如果有大佬了解的可以在下面評論下! 一、環境配置 1.win10 X64&#xff1b; 2.awscli 1.18.91 3.python&#xff08;程序…

51nod 1004 【快速冪】

思路&#xff1a; 掐住最后一位&#xff0c;快速冪一發就好了 #include<cstdio> #include <map> #include<iostream> #include<string.h> #include<algorithm> using namespace std;typedef __int64 LL;int cal(int g,int x) {int ans1;while(g…