C++primer第15章節詳解面向對象程序設計

前言?

  • 面向程序設計基于三個基本概念:數據抽象、繼承和動態綁定。繼承和動態綁定可以使得程序定義與其他類相似但是不完全相同的類;使用彼此相似的類編寫程序時候,可以在一定程度上忽略掉他們的區別。

OOP概述

  • oop(面向程序的設計)核心思想是數據抽象、繼承和動態綁定。使用數據抽象可以將類和接口實現分離;使用繼承,可以定義相似的類型并對相似的類型關系進行建模;使用動態綁定,可以一定程度上忽略相似的內容,而采用統一的方式使用他們的對象。

繼承

  • 通過繼承聯系在一起的類構成了一種層次關系。層次關系的根部叫做基類,其他類則直接或者間接從基類中繼承來,通過繼承得到的類叫做派生類。基類負責定義在層次關系中所有類共同具備的成員,而每一個派生類則會定義各自特有的屬性。

  • 如果派生類想改變基類中包含的特定的函數,根據自己的實際情況進行定制化的開發,基類需要將這個函數聲明為虛函數。派生類需要使用類派生列表,明確指出他是從哪個或者哪些基類派生出來的。類派生的形式是:首先一個分號,后面緊跟著以逗號分隔的基類列表,其中每個基類的前面都可以有訪問說明符。
#include<iostream>
#include "Sales_item.h"
using namespace std;class Quote{
public:string  isbn() const;virtual double net_price(size_t n) const;
};
class Bulk_quote : public Quote{//Bulk_quote繼承了Quote
public:double net_price(size_t n) const override;
};int main(){return 0;
}
  • 派生類必須在其內部對于所有重新定義的虛函數進行聲明。派生類顯示的注明它將使用哪個成員函數改寫基類的虛擬函數,具體的措施是在該函數的形參列表之后增加一個override的關鍵字。

動態綁定

  • 使用動態綁定可以使用相同的代碼分別處理基類和派生類。

double print_total(ostream &os,const Quote &item,size_t n){//計算并且打印給定數量的某種書籍所得的費用//根據傳入item的形參的對象類型調用Quote::net_price//或者使用Bulk_quote::net_pricedouble ret = item.net_price(n);os << "ISBN: " << item.isbn() << " # sold: " << n << "total due :" << ret << endl;return ret;
}
  • 可以使用如下兩種的調用方式,因為下面的函數運行版本是由實參決定的,即在運行的時候選擇函數的版本,所以動態綁定有時候又被稱作運行時綁定。在使用基類的引用(或指針)調用一個虛函數的時候將會發生動態綁定。
//basic的類型是Quote;bulk的類型是Bulk_quote類型
print_total(cout,basic,20);//調用Quote的net_price
print_total(cout,bulk,20);//調用Bulk_quote的net_price

定義基類和派生類

  • 完成對于Quote的定義
  • 繼承關系中根節點的類通常會定義一個虛析構函數,即使該函數不執行任何實際操作也需要定義析構函數。
class Quote{
public:Quote() = default;Quote(const string &book,double sales_price):bookNo(book),price(sales_price){}string  isbn() const{return bookNo};//返回給定數量的書籍的銷售總額//派生類負責改寫并且使用不同的折扣計算方法virtual double net_price(size_t n) const{return n * price;}virtual ~Quote() = default;//對于析構函數進行動態綁定
private:string bookNo;//書籍的ISBN序列號
protected:double price = 0.0;//代表普通狀態下不打折的價格
};

成員函數和繼承

  • 基類需要將兩種成員函數區別開來:1,基類希望派生類進行覆蓋的函數;2,基類需要派生類直接繼承但是不要改變的函數。對于前者,基類通常將其定義為虛函數,在使用指針或者引用調用虛擬函數的時候,該調用將會動態綁定。根據引用或者指針所綁定的對象不同,該引用可能會執行基類或者執行某個派生類。
  • 任何構造函數之外的非靜態函數都可以是虛函數。關鍵字virtual只可以出現在類內部的聲明之前而不能用于對于類外部的函數的定義。對于基類聲明的虛函數,則該函數在派生類中隱式地也是虛函數。成員函數沒有被聲明為虛函數,那么解析過程發生在編譯的時候而不是運行的時候;即虛函數解析過程發生在運行的時候,動態綁定,動態執行。

訪問控制與繼承

  • 派生類可以繼承定義在基類中的成員,但是派生類成員不一定具有對于從基類繼承而來的成員的訪問權。派生類可以訪問公有成員但是不能訪問私有成員。protected用于派生類可以訪問,但是禁止其他用戶進行訪問。

定義派生類

  • 派生類必須通過派生列表明確指出它是從哪個(哪些)基類派生而來的。類派生的形式是:首先一個分號,后面緊跟著以逗號分隔的基類列表,其中每個基類的前面都可以有訪問說明符之一,比如public、protected和private。
  • 派生類必須將其繼承而來的成員函數中需要覆蓋的那些函數重新聲明
  • 大多數類都繼承自一個類,這種機制叫做單繼承

派生類中的虛函數

  • 派生類經常(但不是總是)覆蓋定義它繼承的虛函數,如果派生類中沒有覆蓋基類中的繆一個虛函數,派生類會直接繼承自基類中的對于虛函數的定義。
  • 在形參列表后面、或者在const成員函數的const關鍵字后面、或者在引用成員函數的引用限定符后面添加一個關鍵字override。

派生類對象以及派生類向基類的類型轉換

  • 派生類所具有的對象,不僅包含繼承自基類的對象還具有自己新創建的對象。但是在一個對象中,繼承自基類的部分和派生類自定義的部分不一定是連續存儲的,就是在物理存儲邏輯上,二者不一定占據連續一段存儲空間。
    Quote item; //基類對象Bulk_quote bulk;  //派生類對象Quote *p = &item;  //p指向item(Quote)對象p = &bulk;  //p指向bulk(Bulk_quote)對象的Quote部分Quote *r = &bulk; // r綁定到bulk(Bulk_quote)對象的Quote部分
  • 上面這段代碼通常稱之為派生類到基類的類型轉換,這個過程是由編譯器隱式執行的。即可以將把派生類對象或者派生類對象的引用在需要基類引用的地方。同樣可以將派生類對象的指針用在需要基類指針的地方。

派生類構造函數

  • 盡管派生類對象中含有從基類繼承而來的成員,但是派生類不可以直接初始化這些成員,派生類需要使用基類的構造函數來初始化他的基類部分。派生類對象的基類部分與派生類對象的自己的數據成員都是在構造函數的初始化階段執行初始化操作的。

  • 派生類將自己繼承自基類的那部分交由基類進行初始化,然后初始化派生類自己定義的成員,最后運行派生類的構造函數。除非我們特定指出,否則派生類對象的基類部分會像數據成員一樣被默認初始化。但是如果想使用其他的基類構造函數,需要以類名加圓括號的實參列表的形式為構造函數提供初始化數值。這些實參會幫助編譯器決定使用哪個構造函數來初始化派生類對象的基類部分。

派生類使用基類的成員

  • 派生類可以訪問基類的公有成員和受保護的成員。即派生類的作用域嵌套在基類的作用域之內。即對于派生類的成員來說,使用派生類的成員和使用基類成員的方式是沒有不同的。

繼承與靜態成員

  • 基類定義了一個靜態成員,則在整個繼承體系中只存在該成員的唯一定義。從基類中派生出多少個派生類,對于每個靜態成員來說都只存在唯一的實例。

派生類的聲明

  • 派生類的聲明需要包含類名但是不包含他的派生列表。

被用作基類的類

  • 如果要將某一個類用作基類,則該類必須已經定義而不是簡簡單單的聲明。
  • 一個類不可以派生它本身。即一個類是基類,同時他也可以是一個派生類。比如D1是Base的派生類,而D2又是D2的派生類。那么Base是D1的直接基類,同時也是D2的間接基類。
  • 對于最終的一個派生類來說,他會包含直接基類的所有成員和每一個間接基類的所有對象。

防止繼承的發生

  • 防止自定義的類被繼承,那么就在類的名字后面跟上一個關鍵字final。
  • class NoDerived final{} //NoDerived不能作為基類

類型轉換與繼承

  • 常規情形下,將引用/指針綁定到一個對象上,則引用或者指針的類型應該與對象的類型是一致的。或者對象的類型含有一個可以接受的const類型轉換規則。存在繼承關系的類是一個特殊的存在。
  • 基類的指針或者引用綁定到派生類的對象上,有一層很重要的含義就是不確定被綁定的對象的真實類型是基類還是派生類。

靜態類型與動態類型

  • 表達式的靜態類型是編譯的時候已知的,是變量聲明時的類型或則表達式生成的類型;動態類型是變量或者表達式表示內存中的對象類型,動態類型直到運行時才可知。
  • 如果表達式既不是指針也不是引用,那么他的動態類型和靜態類型是一致的。

不存在從基類向派生類的隱式類型轉換

  • 因為一個基類對象是派生類中的一部分,所以不存在基類向派生類的類型轉換,因為基類不可以訪問派生類中不存在的成員。
  • 既是一個基類指針或者引用綁定在一個派生類度向上,也不可以執行從基類到派生類的轉換。
  • 如果基類中存在多個虛擬函數,在進行類型轉換的時候,可以使用dynamic_cast請求一個類型轉換,該轉換的安全檢查將會在運行的時候進行檢查。如果我們已經知道將某個基類裝換為派生類是安全的,可以使用static_cast來強制覆蓋掉編譯器的檢查工作。

在對象之間不存在類型轉換

  • 使用派生類對象為一個基類對象進行初始化或者賦值的時候,只有派生類對象中的基類部分會被拷貝、移動和賦值;他的派生類部分將會被忽略掉。

?

?

?

?

?

?

?

?

?

?

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

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

相關文章

內存池的線程安全問題

malloc/free 據說老版本libc 有倆個版本&#xff0c;當你連接 pthread庫的時候它就鏈接的是線程安全版&#xff0c;否則不是。在glic 2.2 以上無論怎么都是線程安全的。 new/delete new/delete 封裝的 malloc/free , 如果malloc/free 是它們就是線程安全的。

C++11命名空間的using說明

std::cin 表示從標準輸入讀取內容&#xff0c;此處的作用域操作符::是指編譯器應該從左側名字所示的作用域中尋找右側那個名字。因此std::sin表示使用命名空間std中的cin。 每個名字都需要有獨立的using的聲明 每一個using聲明引入命名空間中的一個成員&#xff0c;比如可以將…

c語音的一些特殊關鍵字

PRETTY_FUNCTION C語言中獲取函數名 C語言中的__LINE__用以指示本行語句在源文件中的位置信息

C++ primer三章二節標準庫類型string

標準庫類型string 標準庫類型string表示可變長的字符序列&#xff0c;使用#include<string>引入頭文件&#xff0c;string定義在命名空間std中。 定義和初始化string對象 如何初始化類的對象是由類的本身決定的&#xff0c;類可以定義很多初始化對象的方式&#xff0c;…

vim 不常見但好用的命令

● 跳躍 ○ 向前跳躍是 f ○ 向后跳躍是 F ● 繼續 ○ 保持方向是 ; ○ 改變方向是 , ● 可以加上 [count] 來加速 ● ^ 是到本行第一個非空字符 ● 0 是到本行第一個字符&#xff0c;不管是不是空格 ● g_ 是到本行最后一個非空字符 ● 兩個按鍵要依次按下 ● $ 跳到本行最后…

加密機組會 會議紀要

2020年9月28日 1&#xff0c;使用基類繼承的機制&#xff0c;調用寫好的函數接口 1&#xff0c;不要 使用Content&#xff08;封裝數據&#xff0c;本質是一個json字符串&#xff09;&#xff0c;1&#xff0c;因為每次使用這個需要對里面的內容進行序列化&#xff0c;轉化成…

c++為什么沒有垃圾回收

垃圾回收 內存清理的另一個方面是垃圾回收。在支持垃圾回收的環境中&#xff0c;程序員幾乎不必顯式地釋放與對象關聯的 內存。運行時庫會在某時刻自動清理沒有任何引用的對象。 與C#和Java不一樣&#xff0c;在C語言中沒有內建垃圾回收。在現代C中&#xff0c;使用智能指針管理…

C++ Vecctor容器淺析

Vector的定義 向量&#xff08;Vector&#xff09;是一個封裝了動態大小數組的順序容器&#xff08;Sequence Container&#xff09;。跟任意其它類型容器一樣&#xff0c;它能夠存放各種類型的對象。可以簡單的認為&#xff0c;向量是一個能夠存放任意類型的動態數組。vector…

C++primer第二章2.4節對于const限定符相關內容進行詳解

const限定符 const對象一旦創建后其數值就不會被再次改變&#xff0c;因此const對象必須初始化。const對象只在文件中有效在不同的文件中使用不同的const來定義不同的常量&#xff0c;那么每個文件定義的變量只會在自己所屬的文件中有效。如果想讓多個文件共享同一個const變量…

二分法的常見問題

mid(leftright)/2; mid (high - low) / 2 low; 這樣寫可以防止left right溢出 ,不過數足夠大是時候該溢還是溢 為什么要取右邊中間數呢&#xff1f;這是因為在區間里 只有 2 個元素的時候&#xff0c;把[left…right]劃分成[left…mid - 1]和[mid…right]這兩個區間&#x…

演示IPFS的一個完整的流程以及針對部分概念的詳解

整體的流程 1&#xff0c;創建ipfs節點 通過ipfs init在本地計算機建立一個IPFS節點本文有些命令已經執行過了&#xff0c;就沒有重新初始化。部分圖片拷貝自先前文檔&#xff0c;具體信息應以實物為準 $ ipfs init initializing IPFS node at /Users/CHY/.ipfs generating 2…

c++ 算法的時間復雜度

一般ACM或者筆試題的時間限制是1秒或2秒。 在這種情況下&#xff0c;C代碼中的操作次數控制在 10^7為最佳。 下面給出在不同數據范國下&#xff0c;代碼的時間復雜度和算法該如何選擇&#xff1a; 1.n≤ 30,指數級別&#xff0c;dis剪枝&#xff0c;狀態壓縮dp 2.n < 100 &g…

簡單工廠模式實現計算器

#include <iostream> #include <vector> #include <string> #include <iostream> #include <map> using namespace std; #define __THROW_ZERO do {cerr << "The dividend is 0" << endl; exit(1);}while(0);/* 簡單工廠處…

TDengine安裝教程

TDengine安裝教程 前言 TDengine的安裝十分簡單&#xff0c;可以有以下三種安裝方式&#xff0c;源碼安裝、通過Docker容器進行安裝、通過安裝包進行安裝。但是使用源碼安裝較為復雜&#xff0c;通過docker的方式最為簡單&#xff0c;但是需要一定docker相關的知識&#xff0…

C++中size_t的學習

size_t的定義 size_t是一種數據相關的無符號類型&#xff0c;它被設計得足夠大以便能夠存儲內存中任意對象的大小。設計 size_t 就是為了適應多個平臺&#xff0c;size_t等效于unsigned short int 或者 unsigned long int 類型&#xff0c;這個過程是動態匹配的。在需要通過數…

策略模式解決商店打折問題

#include <bits/stdc.h> using namespace std; /*策略模式解決商店打折問題*/class Cashsuper { private:/* data */ public:virtual double addcash(double cash) 0;double Getresult(double money){return addcash(money);} };class Cashnormal : public Cashsuper {p…

android 軟件首次運行時引導頁左右滑動效果

很多手機軟件在安裝后首次運行都會進入到引導頁面&#xff0c;再次運行時會進入到主頁面。 多了不說了&#xff0c;先看效果圖&#xff1a; 代碼如下&#xff1a; main.xml <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:an…

C++中size_type類型詳解

介紹 是和string類類型和vector類類型定義相關的類型&#xff0c;用以保存任意string對象或vector對象的長度&#xff0c;標準庫類型將size_type定義為unsigned類型string抽象意義是字符串&#xff0c; size&#xff08;&#xff09;的抽象意義是字符串的尺寸&#xff0c; str…

單一職責原則 實現貪吃蛇代碼的封裝

單一職責原則(SRP),就一個類而言&#xff0c;應該僅有一個引起它 變化的原因。 一個c語言的貪吃蛇代碼 如何使用單一職責原則封裝成c面向對象呢 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> #include <wi…

android ProgressBar實現掃描SD卡文件 + SimpleAdapter綁定ListView

代碼 activity_main.xml <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:layout_height"match_parent"to…