C++ primer plus 類和對象上

目錄

前言

一? 接口的設計

二? 方法的設計和使用

三? 構造函數

?四? 析構函數

五? 析構函數和構造函數小結

總結


前言

前面已經描述了很多有關于類和對象的知識了,所以我們直接開始上手操作


一? 接口的設計

首先我們要知道什么是接口
接口是一個共享框架,供兩個系統(如在計算機和打印機之間或者用戶或計算機程序之間)交互時使 用;例如,用戶可能是您,而程序可能是字處理器。 使用字處理器時,您不能直接將腦子中想到的詞傳輸 到計算機內存中,而必須同程序提供的接口交互
您打鍵盤時,計算機將字符顯示到屏幕上;您移動鼠標時,計算機移動屏幕上的光標;您無意間單擊鼠標時,計算機對您輸入的段落進行奇怪的處理。 程序接 口將您的意圖轉換為存儲在計算機中的具體信息。 對于類,我們說公共接口。 在這里,公眾 (public) 是使用類的程序,交互系統由類對象組成,而接口由編寫類的人提供的方法組成。接口讓程序員能夠編寫與類對象交互的代碼,從而讓程序能夠使用類對象。 例如,要計算stnng對象中包含多少個字符,您無需打開對象,而只需使用 stríng 類提供的 size()方法。 類 設計禁止公共用戶直接訪問類,但公眾可以使用方法size()。 方法size()是用戶和 string類對象之間的公共接口的組成部分。 通常,方法getline()是 istream 類的公共接口的組成部分,使用 cin 的程序不是直接與 cin 對象內部交互來讀取一行輸入,而是使用 getline()。 如果希望更人性化,不要將使用類的程序視為公共用戶,而將編寫程序的人視為公共用戶。 然而,要使用某個類,必須了解其公共接口,要編寫類,必須創建其公共接口

通常, C++程序員將接口(類定義)放在頭文件中,并將實現(類方法的代碼〉放在源代碼文件中
我們要養成一個習慣,為了區分,我們類的首字母是需要大寫的,接口往往就是我們設計在public里的函數,然后通過這個可以間接訪問到里面private里面私密變量

下面我們就來設計一個接口

#ifndef __COOL__H__
#define __COOL__H__#include<string>class Stock {
private:std::string company;long shares;long share_vale;long total_vale;void set_tot() {total_vale = shares * share_vale;}public:void acquire(const std::string& co, long n, double pr);void buy(long num, double price);void sell(long num, double price);void updata(double price);void show();
};#endif

以上是我在cool.h里設計的一個類
那么這里的public的意思就是公用的,也就是說可以在外部進行訪問
關鍵字publlc標識組成類的公共接口的類成員(抽象)
private就是私密的,也就是只有類里面才可以進行訪問,外部是訪問不到的

這個里面的數據是隱藏的
數據隱藏不僅可以防止直接訪問數據,還讓開發者(類的用戶)無需了解數據是如何被表示的。例如, show( )成員將顯示某支股票的總價格(還有其他內容),這個值可以存儲在對象中(上述代碼正是這樣做 的),也可以在需要時通過計算得到。從使用類的角度看,使用哪種方法沒有什么區別。 所需要知道的只是 各種成員函數的功能:也就是說,需要知道成員函數接受什么樣的參數以及返回什么類型的值原則是將實現細節從接口設計中分離出來。如果以后找到了更好的、實現數據表示或成員函數細節的方法,可以對 這些細節進行修改,而無需修改程序接口,這使程序維護起來更容易

其實C++如果你沒有設置他是public還是private的話,那么就是默認是private,只是我們在平時編寫代碼的時候要養成好的習慣,這樣也可以增加可讀性

在C++里面結構體也是可以使用方法的也就是放入函數,但是與類不一樣的地方就是,結構體無論是什么數據還是方法都是公開的,但是class可以設置公開與隱藏
?

當我們在private里面設置了一個函數,這個函數就是一個內聯函數,但是下面public不是內聯函數,那個只是一個接口,而不是一個內聯函數,如果你想把他編程內聯函數的話,那么就直接在編寫函數

二? 方法的設計和使用

#include<iostream>
#include"cool.h"//表示公司首次購買股票
void Stock::acquire(const std::string& co, long n, double pr) {company = co;if (n < 0) {std::cout << "Number of shares can't be negative;"<< company << "shares set to 0.\n";shares = 0;}else {shares = n;share_vale = pr;set_tol();}
}//增加股票
void Stock::buy(long num, double price) {if (num > 0) {std::cout << "Number of shares can't be negative;"<< "Transaction is aborted.\n";}else {shares += num;share_vale = price;set_tol();}
}//減少股票
void Stock::sell(long num, double price) {using std::cout;if (num < 0) {std::cout << "Number of shares can't be negative;"<< "Transaction is aborted.\n";}else if (num > shares) {cout << "You can't sell more than you have!"<< "Transaction is aborted.\n";}else {shares -= num;share_vale = price;set_tol();}
}//更新
void Stock::update(double price) {share_vale = price;set_tol();
}//展示
void Stock::show() {std::cout << "compay: " << company<< "shares:" << shares << '\n'<< "share price: $" << share_vale<< "total worth: $" << total_vale << '\n';
}

?這個就是我們根據類來進行編寫這個成員函數,這個成員函數是可以簡介訪問private里的值的
?

接下來就是書寫就是這個使用這個方法

#include<iostream>
#include"cool.h"
using namespace std;int main() {Stock cat;cat.acquire("zhang", 1, 19.25);cat.show();cat.buy(3, 19.23);cat.show();cat.sell(1, 20);cat.show();return 0;
}

一般來說數據是放到private里,public一般放的是方法?

三? 構造函數

1? 構造函數
由于我們很多變量都是需要初始化的,比如我們定義一個變量要對他進行初始化,但是再類里面,我們要對private里面的變量進行初始化,我們通過直接的訪問進行初始化肯定是不行的,但是我們可以通過函數來進行修改,我們知道public是可以間接訪問到private里面的變量的

就比如我們上面有一個函數

void Stock::acquire(const std::string& co, long n, double pr) {company = co;if (n < 0) {std::cout << "Number of shares can't be negative;"<< company << "shares set to 0.\n";shares = 0;}else {shares = n;share_vale = pr;set_tol();}
}

但是這個不是構造函數,這個只是其中的一個成員函數
那么我們要怎么改寫成構造函數
1? 構造函數無返回值
2? 函數名字與類的名字相同
3? 形參的名字不可以跟private賦值的成員變量的名字一樣

//表示公司首次購買股票
Stock::Stock(const std::string& co, long n, double pr) {company = co;if (n < 0) {std::cout << "Number of shares can't be negative;"<< company << "shares set to 0.\n";shares = 0;}else {shares = n;share_vale = pr;set_tol();}
}聲明
Stock(const std::string& co, long n, double pr);

對于名稱的設置



這樣我們就得到了一個構造函數,但是我們要怎么使用這個構造函數呢?
使用構造函數的方式有兩個
1? 顯式使用構造函數
2? 隱式使用構造函數


1? 顯式??Stock food = Stock("World Cabbage" , 250 , 1.25 );
2? 隱式??Stock garmnent ("Furry Mason", 50 , 2.5) ;??
等同于Stock garment = Stock(" Furry Mason" , 50 , 2.5));
3? 每次創建類對象(甚至使用new動態分配內存)時C++都使用類構造函數。下面是將構造函數與new 一起使用的方法: Stock *pstock = new Stock("Electroshock Games ", 18 , 19 .0);

2? 默認構造函數
當我們類里面沒有寫構造函數的話,那么編譯器是會給類一個默認構造函數,但是編譯器給的默認構造函數里面是空的,什么都沒有,就像下面這個例子一樣
Stock: :Stock() { }

我們該怎么創建構造函數呢?
下面有兩個方法
方法一:基于上述構造函數在函數的聲明里面加入默認值

Stock(const std::string& co = "no name", long n = 0, double pr = 0);

?這樣我們就可以設置默認值了

方法二:寫一個沒有任何參數的默認構造函數
這個是通過函數的重載寫的,由于只能有一個默認構造函數,因此不要同時采用這兩種方式

我們需要區分默認構造和構造,還要學會使用構造?

?構造函數的陷阱
首先我們創建一個構造函數的時候,則編譯器不會再給我提供默認構造函數,所以當我們創建一個變量,沒有調用自定義的構造函數將變量進行初始化的話,那么就會報錯,因為沒有初始值

?四? 析構函數

當我們在使用完類的時候,我們的對象是需要"釋放"的
就比如我們在寫了一個角色的時候,角色的重生是利用構造函數,角色的死亡是利用析構函數
當我們在沒有寫析構函數的時候,計算機是會給我們默認析構函數,這個默認的析構函數就類似于我們默認的構造函數,這個編譯器是空的參數列表并且代碼塊是空的,如果我們用默認構造函數去用new創建一個對象,然后我們就使用析構函數使用delete來釋放這個new釋放的對象

析構函數是無返回值和沒有類型的聲明的

什么時候調用析構函數呢?
這個是由我們編譯器決定的
如果是靜態的,析構函數是在程序結束的時候被調用
如果是自動的,析構函數是在這個代碼塊執行完被調用
如果是new創建的,析構函數是在delete釋放之后被調用

我們來改進一下我們之前的代碼,加入我們的析構函數
首先我們更改一下我們的頭文件

#ifndef __COOL__H__
#define __COOL__H__#include<string>class Stock {
private:std::string company;long shares;long share_vale;long total_vale;void set_tol() {total_vale = shares * share_vale;}public:Stock(const std::string& co = "no name", long n = 0, double pr = 0);~Stock();void buy(long num, double price);void sell(long num, double price);void update(double price);void show();
};#endif

工具函數?

#include<iostream>
#include"cool.h"//表示公司首次購買股票
Stock::Stock(const std::string& co, long n, double pr) {company = co;if (n < 0) {std::cout << "Number of shares can't be negative;"<< company << "shares set to 0.\n";shares = 0;}else {shares = n;share_vale = pr;set_tol();}
}Stock::~Stock() {std::cout << "bey bey" << std::endl;
}//增加股票
void Stock::buy(long num, double price) {if (num < 0) {std::cout << "Number of shares can't be negative;"<< "Transaction is aborted.\n";}else {shares += num;share_vale = price;set_tol();}
}//減少股票
void Stock::sell(long num, double price) {using std::cout;if (num < 0) {std::cout << "Number of shares can't be negative;"<< "Transaction is aborted.\n";}else if (num > shares) {cout << "You can't sell more than you have!"<< "Transaction is aborted.\n";}else {shares -= num;share_vale = price;set_tol();}
}//更新
void Stock::update(double price) {share_vale = price;set_tol();
}//展示
void Stock::show() {std::cout << "compay: " << company << " "<< "shares:" << shares << '\n'<< " share price: $" << share_vale<< " total worth: $" << total_vale << '\n';
}

主函數

#include<iostream>
#include"cool.h"
using namespace std;int main() {Stock cat("cat", 10, 100.19);cat.show();Stock dog("dog", 5, 105.19);dog.show();
}

然后我們就直接寫好了,我們運行一下看看結果是什么

我們可看到這個結果這個dog是在上面的,但是這個cat是在下面的,這就說明了這個對象的存儲是按照棧的順序進行存儲的

在C++11 中,可將列表初始化語法用于類嗎?
可以,只要提供與某個構造函數的參數列表匹配的內容, 并用大括號將它們括起:

Stock hot_tip = {"erivatives Plus Plus", 100, 45 .0}; 
Stock j ock {" Sport Age Storage, Inc" }; 
Stock temp {}; 

?這種方法不推薦,但是要知道有這個方式

const成員函數
下面我們來看一個樣例

const Stock land = Stock("Kludgehorn Properties") ; 
land.show () ;

這個是不被允許的,為什么?因為我們這個成員是const的常量,然后我們來看看我們show函數里面的代碼

void Stock::show() {std::cout << "compay: " << company << " "<< "shares:" << shares << '\n'<< " share price: $" << share_vale<< " total worth: $" << total_vale << '\n';
}

?其實這個代碼里面并沒有常量指針進行接受,或者常量引用來進行接受,那么就會導致編譯器認為,你這個是不安全的,不可以保護company這個常量,所以就會報錯,因為編譯器認為不安全

這個時候我們除了用const指針和const引用的方法,還有一個方法就是在這個函數的末尾加上const來進行表示

void show () const; 
/ / promises not to change invoking object void stock::show() const 
/ / promises not to change invoking object 

我們在函數的聲明和函數的末尾都需要加上const來承諾這個是不可以改變的
以這種方式聲明和定義的類函數被稱為 const成員函數。就像應盡可能將const引用和指針用作函數形 參一樣,只要類方法不修改調用對象,就應將其聲明為 const,這種方式被稱為常量成員函數

五? 析構函數和構造函數小結

下面我們來小結一下結構函數和析構函數

結構函數
結構函數的名字和類的名字是一樣的,前面也要記得加上類名字和作用域
首先結構函數分為結構函數和默認結構函數

結構函數就是我們自定義的,需要傳參數進行初始化賦值的,如果我們創建了之后,編譯器就不會出現再給我們提供默認構造函數了,如果你不調用進行初始化,那么就會報錯,報錯為找不到默認函數,所以我們創建了就要進行初始化
1? 顯式??Stock food = Stock("World Cabbage" , 250 , 1.25 );
2? 隱式??Stock garmnent ("Furry Mason", 50 , 2.5) ;??

默認構造函數
默認構造函數就是我們不進行傳參數,然后直接進行賦值
默認構造函數是只有隱式
1? 隱式? 就是定義變量就好了,為什么沒有顯示,上面有

析構函數
析構函數就是我們需要注意它的存儲方式
還有就是析構函數就是我們需要注意傳參是const的時候,再函數聲明和函數加上const的,或者需要利用常量引用和常量指針

如果我們只有一個參數的時候,我們可以直接這么初始化

Bozo FUFU = 32

直接用等于號


總結

我們學習了怎么設計類,頭文件應該放什么,方法應該放到哪里,還有就是析構函數和構造函數需要注意的

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

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

相關文章

css模擬雷達掃描動畫

<div class"radar-scan"><div class"radar-container" /></div> 樣式&#xff1a; .radar-scan {background-image: linear-gradient(0deg,transparent 24%,rgba(32, 255, 77, 0.15) 25%,rgba(32, 255, 77, 0.15) 26%,transparent 27%,…

AdaLoRA 參數 配置:CAUSAL_LM“ 表示因果語言模型任務

AdaLoRA 參數 配置:CAUSAL_LM" 表示因果語言模型任務 config = AdaLoraConfig( init_r=16, # 增加 LoRA 矩陣的初始秩 lora_alpha=32, target_modules=[“q_proj”, “v_proj”], lora_dropout=0.1, bias=“none”, task_type=“CAUSAL_LM” ) 整體功能概述 AdaLoraCon…

C# 集合

集合 概述集合接口和類型列表(ArrayList, List)隊列(Queue)棧(Statck)鏈表(LinkedList)有序表(SortedList)字典Lookup類其他字典類 HashSet(不重復項的無序列表)位數組BitArrayBitVector32 性能 概述 數組和Array類。數組的大小是固定的。如果元素個數是動態的&#xff0c;就應…

WebSocket與MQTT協議深度對比:選擇合適的通信協議

在現代互聯網應用中&#xff0c;實時通信變得愈發重要。隨著物聯網&#xff08;IoT&#xff09;和實時數據流的普及&#xff0c;選擇合適的通信協議顯得尤為關鍵。WebSocket和MQTT是當前最為流行的兩種協議&#xff0c;它們各自有不同的應用場景、優缺點以及性能特點。在這篇文…

ELK(Elasticsearch、Logstash、Kbana)安裝及Spring應用

Elasticsearch安裝及Spring應用 一、引言二、基本概念1.索引&#xff08;Index&#xff09;2.類型&#xff08;Type&#xff09;3.文檔&#xff08;Document&#xff09;4.分片&#xff08;Shard&#xff09;5.副本&#xff08;Replica&#xff09; 二、ELK搭建1.創建掛載的文件…

MacOS 15.3.1 安裝 GPG 提示Error: unknown or unsupported macOS version: :dunno

目錄 1. 問題鎖定 2. 更新 Homebrew 3. 切換到新的 Homebrew 源 4. 安裝 GPG 5. 檢查 macOS 版本兼容性 6. 使用 MacPorts 或其他包管理器 7. 創建密鑰&#xff08;生成 GPG 簽名&#xff09; 往期推薦 1. 問題鎖定 通常是因為你的 Homebrew 版本較舊&#xff0c;或者你…

C++:類和對象(從底層編譯開始)詳解[前篇]

目錄 一.inline內聯的詳細介紹 &#xff08;1&#xff09;為什么在調用內聯函數時不需要建立棧幀&#xff1a; &#xff08;2&#xff09;為什么inline聲明和定義分離到兩個文件會產生鏈接錯誤&#xff0c;鏈接是什么&#xff0c;為什么沒有函數地址&#xff1a; 二.類&…

C++中,存儲持續性、作用域和鏈接性

在C++中,存儲持續性、作用域和鏈接性是變量和函數的重要屬性,它們共同決定了變量的生命周期、可見性以及跨文件訪問能力。以下是詳細的總結: 1. 存儲持續性(Storage Duration) 存儲持續性指變量在內存中的生命周期,分為四類: 自動存儲持續性(Automatic) 局部變量(函…

四種 No-SQL

在一個常規的互聯網服務中&#xff0c;讀取與寫入的比例大約是 100:1 到 1000:1。然而&#xff0c;從硬盤讀取時&#xff0c;數據庫連接操作耗時&#xff0c;99% 的時間花費在磁盤尋址上。 為了優化讀取性能&#xff0c;非規范化的設計通過添加冗余數據或分組數據來引入。下述…

【 Manus平替開源項目】

文章目錄 Manus平替開源項目1 OpenManus1.1 簡介1.2 安裝教程1.3 運行 2 OWL2.1 簡介2.2 安裝教程2.3 運行 3 OpenHands&#xff08;原OpenDevin&#xff09;3.1 簡介3.2 安裝教程和運行 Manus平替開源項目 1 OpenManus 1.1 簡介 開發團隊: MetaGPT 核心貢獻者&#xff08;5…

【Linux 服務之ollama 部署過慢問題】

特別慢的 curl -fsSL https://ollama.com/install.sh | sh參考 方法1 export OLLAMA_MIRROR"https://ghproxy.cn/https://github.com/ollama/ollama/releases/latest/download" curl -fsSL https://ollama.com/install.sh | sed "s|https://ollama.com/downl…

療養院管理系統設計與實現(代碼+數據庫+LW)

摘 要 傳統辦法管理信息首先需要花費的時間比較多&#xff0c;其次數據出錯率比較高&#xff0c;而且對錯誤的數據進行更改也比較困難&#xff0c;最后&#xff0c;檢索數據費事費力。因此&#xff0c;在計算機上安裝療養院管理系統軟件來發揮其高效地信息處理的作用&#xf…

Web后端開發之Maven

Maven Mven是apache旗下的一個開源項目&#xff0c;用來管理和構建java項目的工具。 通過一小段描述信息來管理項目。 Maven的作用 1.依賴管理&#xff1a;方便快捷的管理項目依賴的資源&#xff08;jar包&#xff09;&#xff0c;避免版本沖突問題 以前用某個jar包需要下載…

在線招聘小程序:AI簡歷篩選與精準職位推薦服務

當AI算法遇上小程序開發:重新定義「人崗匹配」的智能招聘革命 一、傳統招聘困境:求職者與企業為何總在「錯過」? 在數字化浪潮下,企業HR日均需處理數百份簡歷,卻仍有60%的崗位因匹配效率低下而空置;求職者海投簡歷后,近八成用戶表示從未收到精準反饋。這種雙向資源錯配…

Linux文件IO——緩沖區磁盤上的文件管理

前言 什么是緩沖區&#xff1f; 緩沖區是內存空間上的一小段內存&#xff0c;我們平常在寫程序的時候&#xff0c;其實是很難感知到緩沖區的存在的&#xff0c;接下來看一段代碼&#xff0c;可以很好地體現緩沖區的存在。 #include<stdio.h> #include<unistd.h> in…

Java中如何去自定義一個類加載器

之前寫過一篇&#xff0c;關于 類加載器和雙親委派的文章&#xff0c;里邊提到過可以根據自己的需要&#xff0c;去寫一個自定義的類加載器&#xff0c;正好有人問這個問題&#xff0c;今天有時間就來手寫一個自定義的類加載器&#xff0c;并使用這個自定義的類加載器來加載一個…

X86 RouterOS 7.18 設置筆記六:端口映射(IPv4、IPv6)及回流問題

X86 j4125 4網口小主機折騰筆記五&#xff1a;PVE安裝ROS RouterOS X86 RouterOS 7.18 設置筆記一&#xff1a;基礎設置 X86 RouterOS 7.18 設置筆記二&#xff1a;網絡基礎設置(IPV4) X86 RouterOS 7.18 設置筆記三&#xff1a;防火墻設置(IPV4) X86 RouterOS 7.18 設置筆記四…

代碼隨想錄|二叉樹|21合并二叉樹

leetcode:617. 合并二叉樹 - 力扣&#xff08;LeetCode&#xff09; 題目 給定兩個二叉樹&#xff0c;想象當你將它們中的一個覆蓋到另一個上時&#xff0c;兩個二叉樹的一些節點便會重疊。 你需要將他們合并為一個新的二叉樹。合并的規則是如果兩個節點重疊&#xff0c;那么…

LDR6500在Type-C轉DP視頻雙向互傳方案

LDR6500在Type-C轉DP視頻雙向互傳方案中扮演著核心角色&#xff0c;以下是對該方案的詳細解析&#xff1a; 一、LDR6500芯片概述 LDR6500是樂得瑞科技針對USB Type-C標準中的Bridge設備而開發的USB-C DRP&#xff08;Dual Role Port&#xff0c;雙角色端口&#xff09;接口USB…

Vue3中 ref 與 reactive區別

ref 用途: ref 通常用于創建一個響應式的基本類型數據&#xff08;如 string、number、boolean 等&#xff09;&#xff0c;但它也可以用于對象或數組 返回值: ref 返回一個帶有 .value 屬性的對象&#xff0c;訪問或修改數據需要通過 .value 進行 使用場景: …