類的默認訪問屬性是private
給類添加成員函數不會影響類對象的大小
class CBox
{
.....
CBox()=default; //default關鍵字指定,無參CBox構造函數應包含在類中,就是默認構造函數
}
在構造函數頭初始化成員比使用賦值語句的效率高
對於const或引用類型的類成員,其初始化方式是無法選擇的,唯一的方式是在構造函數中使用成員初始化列表。
構造函數聲明爲explicit,則只能顯示地調用它,且不用於隱式轉換
友元函數不是類的成員,它只是擁有特殊權限的普通全局函數
任何成員函數執行時,都自動包含一個名爲this的隱藏指針,它指向調用該函數時使用的對象
僅當某個函數時類成員時,將其聲明爲const纔有意義,其作用是使該函數中的this指針成爲const,這意味着不能在該函數的定義內在賦值語句左邊寫上類的數據成員。const成員函數不能調用同類非const成員函數
每個靜態數據成員只有一個實例存在,與定義了多少類對象無關,只有希望它初始值非0才需要初始化它
靜態成員函數只能使用靜態數據成員,即使本類的任何對象都不存在,它們也能存在並被使用
用指針動態創建對象後,調用delete操作符將在釋放該對象佔用的內存前首先調用該對象的析構函數。
爲了避免對複製構造函數的無窮調用,必須將形參指定爲const引用
如果動態地爲類的成員分配空間,則必須實現複製構造函數
重載操作符
class CBox;
CBox box1;
CBox box2;
if(box1<box2)//等價於
if(box1.operator<(box2))
當定義以現在的同類對象進行初始化的類對象,或者通過以傳值方式給函數傳遞對象時,調用默認複製構造函數。
當賦值語句的左邊和右邊是同類類型的對象時,調用默認賦值運算符。如果需要給類的數據成員動態分配空間,則必須實現賦值運算符。
區分重載運算符前綴和後綴形式的首要方法是利用形參列表。前綴形式沒有形參,後綴形式又一個int類型的形參,後綴運算符函數的形參只是爲了將其同前綴形式區別開來,除此之外它在函數實現中沒有任何用處。
在後綴形式中,操作數是在表達式中使用其當前值之後遞增的,要實現這一點,需要再遞增當前對象之後創建當前對象的副本,並在修改過當前對象之後返回新創建的副本對象
函數對象提供了一種方式,可以將函數作爲實參傳遞給另一個函數
正常的低效率 moto3=moto1+moto2;就存在2個複製臨時對象的操作
CMessage operator+(const CMessage& aMess) const
{
cout<<"add operator function called"<<end;
size_t len{strlen(m_pMessage)+strlen(aMess.m_pMessage)+1};
CMessage message;
message.m_pMessage=new char[len];
strcpy_s(message.m_pMessage,len,m_pMessage);
strcat_s(message.m_pMessage,len,aMess.m_pMessage);
return message;
}
高效版本
CMessage& operator=(CMessage&& aMess)
{
cout<<"Move assignment opeartor function called".<<endl;
delete[] m_pMessage;
m_pMessage=aMessage.m_pMessage;
aMessage.m_pMessage=nullptr;
return *this;
}
具有rvalue引用形參的複製構造函數稱爲移動構造函數。
如果在類中定義operator=()成員函數和複製構造函數時,將形參定義爲非常量rvalue引用,則需要確保也定義了具有const lvaue引用形參的標準版本。否則,編譯器會根據它們的默認版本,逐一成員進行復制。
utility頭文件提供了std::move()函數,可以強制使一個lvalue變成rvalue。避免當一個類包含另一個類而導致重新效率地下問題
模板類的定義方式
template <typename T>
class CSamples
{
T max() const;
}
template<typename T>
T CSamples<T>::max() const
{
T theMax{m_Values[0]};
...
}
utility頭文件聲明的std::forward()函數模板,如果給它傳送一個rvalue引用實參,它就把該實參返回爲rvalue,如果給它傳送一個lvalue引用,它就把該實參返回爲一個lvalue引用。稱爲完美轉發,就是傳進來是rvalue就讓它繼續是rvalue,是lvalue就繼續
函數模板的默認實參
template<typename T,typename R=double>
R sigma(T values[],size_t count)
{
...
}
使用時
sigma<int,float>(...)
尖括號必不可少,即使沒有形參值,也不能省略它們
模板特列。模板特例是爲了一組特殊的形參值制定的一個額外的模板定義
template<>
CBox average(CBox boxer[],size_t count)
{
...
}
帶空尖括號的第一行代碼高速編譯器,這是已有模板的一種特殊情況,模板實參由編譯器通過第一個實參的類型來判斷
當實參滿足模板特例定義的形參時就會調用模板特例,還有部分特例的情況
template<typename T>
class CSamples<T*>
template<size_t Size>
class CSamples<CBox,Size>
#pragma once //防止該文件內容多次嵌入到源代碼中。
#ifndef BOX_H //他們是任何C++編譯器都支持的指令,只要沒有定義符號BOX_H,編譯過程中就將嵌入#ifndef指令後面一
#define BOX_H // 值到#endif指令之前的所有代碼行。#Ifndef後面那一行定義了符號BOX_H,從而確保該頭文件不被二次
#endif //嵌入
string內容
length()成員函數來查看字符串對象所封裝的字符串長度。
string bees(7,'b') //string is "bbbbbbb"
string sentence{"this sentence is false."} string part{sentence,5,11}//從第五位開始,11個字符。
string每次用+運算符連接兩個字符串時,都是在創建一個新的string對象,會帶來開銷,但是會儘可能使用移動語義,+運算符創建一個包含合併後的字符串的新字符串對象。+=運算符將作爲右操作數的字符串或字符附加到作爲左操作數的string對象後面,因此直接修改string對象,而不創建新的對象。
用at()成員函數與用[]操作符得到的結果相同。但是利用下標值得速度比使用at()函數塊,但缺點是沒有檢查索引的有效性,如果索引超出了範圍,那麼使用下標操作符的結果將不確定,另一方面,使用at(),如果索引無效會拋出一個out_of_range異常。
substr()函數的第一個實參是要提取的子字符串中的第一個字符,第二個實參是子字符串中的字符個數
append()函數,可以在字符串末尾添加一個或多個字符
swap()成員函數可以交換封裝在兩個string對象中的字符串
c_str()如果需要將一個字符串對象轉換爲以空字符結尾的字符串,但內容不變。
find_first_of(),find_last_of(),find_first_not_of(),find_last_not_of()等等。。。
派生類不繼承的基類成員僅有析構函數,構造函數以及任何重載賦值運算符的成員函數。
字符串的長度不影響對象的大小,因爲容納字符串的內存是在空閒存儲器上分配的
創建派生類對象的基類部分實際上屬於基類構造函數而非派生類構造函數的任務,基類構造函數總是先於派生類構造函數被調用,因爲基類是派生類構建的基礎,所以必須先創建基類。
基類的保護成員可以由派生類的函數訪問。
派生類對象析構函數的調用順序與構造函數相反,銷燬對象時首先調用派生類的析構函數再調用基類的析構函數。
如果將基類的成員聲明爲private,則它們在派生類中永遠都不可訪問
如果將基類聲明爲Public,其成員在派生類中的訪問級別保持不變。
如果將基類聲明爲protected,其public成員在派生類中將成爲protected.
有時需要確保不能把類用作基類,爲此可以把類指定爲final,如:class CBox final
類友元關係是不可繼承的
要使某個函數表現出虛函數的行爲,該函數再任何派生類中都必須有與基類函數相同的名稱,形參列表和返回類型。使用override修飾符可以告訴編譯器派生類中的某虛函數重寫了基類中的虛函數。如virtual double volume() const override,這時編譯器會檢查基類中是否有相同的簽名volumn()函數,如果沒有,會收到一個錯誤消息
有時希望禁止重寫類的某個函數成員,可以把成員函數指定爲final.
抽象類可以擁有數據成員和函數成員,純虛函數是否存在是判斷給定的類是否是抽象類的唯一條件,同樣的道理,抽象類可以擁有多個純虛函數,這種情況下,派生類必須給出基類中每個純虛函數的定義,否則將仍然是抽象類。
dynamic_cast專門適合用於基類和派生類之間的轉換,不僅可以應用於指針,也可以應用於引用,dynamic_cast與static_cast之間的區別在於,dynamic_cast操作符在運行時檢查轉換的有效性,如果操作無效,則結果爲nullptr
嵌套類可以自由訪問封裝類的所有靜態成員,非靜態不能訪問,封裝類只能訪問嵌套類的公有成員。