目錄
前言
一? 接口的設計
二? 方法的設計和使用
三? 構造函數
?四? 析構函數
五? 析構函數和構造函數小結
總結
前言
前面已經描述了很多有關于類和對象的知識了,所以我們直接開始上手操作
一? 接口的設計
首先我們要知道什么是接口
接口是一個共享框架,供兩個系統(如在計算機和打印機之間或者用戶或計算機程序之間)交互時使 用;例如,用戶可能是您,而程序可能是字處理器。 使用字處理器時,您不能直接將腦子中想到的詞傳輸 到計算機內存中,而必須同程序提供的接口交互
您打鍵盤時,計算機將字符顯示到屏幕上;您移動鼠標時,計算機移動屏幕上的光標;您無意間單擊鼠標時,計算機對您輸入的段落進行奇怪的處理。 程序接 口將您的意圖轉換為存儲在計算機中的具體信息。 對于類,我們說公共接口。 在這里,公眾 (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
直接用等于號
總結
我們學習了怎么設計類,頭文件應該放什么,方法應該放到哪里,還有就是析構函數和構造函數需要注意的