候捷C++深入學習

XodeChou發表於2024-04-11

C++進階學習

標頭檔案的防衛式宣告

#ifndef MYCLASS
#define MYCLASS

Header file content

#endif

成員函式的保護

  • 如果輸入引數採用“值傳遞”,由於函式將自動產生臨時變數用於複製該引數,該輸入引數本來就無需保護,所以不要加 const 修飾。例如不要將函式 void Func1(int x) 寫成 void Func1(const int x)
  • 如果引數作為輸出引數,不論它是什麼資料型別,也不論它採用“指標傳遞”還是“引用傳遞”,都不能加 const 修飾,否則該引數將失去輸出功能(因為有 const 修飾之後,不能改變他的值)。
  • 果引數作為輸入引數,可以防止資料被改變,起到保護作用,增加程式的健壯性,建議是能加const儘量加上
int getToValue() const //此處需要加入const,防止shu'j
  {
    return m_nTo; //this->m_nTo
  }

返回值最佳化

return by reference 的情況包括一個value加到另一個value的情況,不適用於兩個value相互作用產生新的value的情況,正如黃色內的內容

image-20230223193143584

return by reference 不需要知道接收者是以reference形式接收的

image-20230223193445064

特殊的過載運算子

<< 不能寫為成員函式,只能寫全域性函式,因為cout不能識別複數型別

inline complex
conj (const complex& x){
    return complex(real(x) , -imag(x));
}

#include <iostream>
ostream& //防止第二種情況的發生,需要“cout<<c1”的型別為cout才能接收第二個conj
operator << (ostream& os , const complex& x){ //ostream沒有const因為
                                         //向cout內傳入資料就是在改變cout
    return os << '(' <<real(x)<<','<<imag(x)<<')';
}
int main()
{
    complex c1(2 , 1);
    cout<<conj(c1);
    cout<<c1<<conj(c1); //②
}

Inline函式

Inline函式的使用

如果是在類中,函式的如果在類定義的時候進行定義,那麼,加不加關鍵字 inline 並沒有什麼異樣,因為,這樣的函式都會被預設為是行內函數。

詳細:C++經驗(十一)-- (inlining)行內函數的使用_slowlytalk的部落格-CSDN部落格

三種特殊的函式

//建構函式
inline
String::String(const char* cstr = 0){//引數為常量指標
    if(cstr){
        m_data = new char[strlen(cstr) + 1];//"+1"的原因是字串最後還有一個                                               結束位
        strcpy(m_data , cstr);  
   }
    else{
        m_data = new char[1];
        *m_data = '\0';
    }
}

//解構函式
inline
String::String(){
    delete[] m_data;
}

//複製建構函式
inline
String::String(const String& str){
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data , str.m_data);
}

//複製賦值函式
inline
String& String::String operator=(const String& str){
    if(this == &str){
        return *this; //監測自我賦值,
    }
    
    delete[] m_data;
    m_data = new char[strlen(strlen m_data) + 1];
    strcpy(m_data , str.m_data);
    return *this;
}

image-20230227202048944

image-20230227202005994

記憶體管理

若使用array new 則一定要使用array delete

String *p = new String[3];
...
delete[] p; //因為delete的陣列所以要有[],否則無法徹底清除

堆和棧

class Complex {....}
...
{
    Complex c1(1,2);//c1所佔用的空間來自於Stack
    Complex* p = new Complex(3);//p是個臨時物件,空間是從Heap的分配而來的
}    

Stack的生命期結束之後清理,也是auto object

static Stack的生命在作用域結束之後仍然存在,在函式結束後才會結束

global object 在類結束後再消失

delete:先呼叫dtor(解構函式)後釋放memory

new:先分配memory 後呼叫ctor(建構函式)

static

一般常量型別(未被static修飾)、引用型別,在類內部即可實現初始化,在類外實現初始化的必定是static型別(當然一部分的靜態成員,也即同時又是const和integral type的,可在類內初始值設定,這一語法特性並非為所有的編譯器所支援,所以一種推薦的做法,即是凡是static型別的,我們總在類外進行初始化,哪怕它在類內已進行初始值設定,只要在類外初始化時不修改其值):

int Test::si = 0;
const int Test::sci = 1;
const double Test::scd = 99.0;

函式模板

遇到不能立刻確定的資料和函式型別,可以用function template 來暫時定義。

template <class T>
    inline
    const T& min(const T& a , const T& b){
return b < a ? b : a;}

Composition 表示has-a

template <class T>
class queue{
    protected:
    deque<T> c;//引用了別的類的資料
};

class deque{
 protected:
    Itr<T> star;// 同上
    Ttr<T> finish;
    T** map;
    unsigned int map_size;
};

struct Ttr{
    T* cur;
    T* first;
    T* last;
    T** node;
};

組合下的構造和析構:

構造順序為由內而外,析構為由外而內

Delegation Composition by reference

image-20230313212706042

vector 的一些基礎操作

向尾部加入元素時由兩種函式,一個是push_back(),另一個是emplace_back()

  1. push_back 可以接收左值也可以接受右值,接收左值時使用複製構造,接收右值時使用移動構造
  2. emplace_back 接收右值時呼叫類的移動構造
  3. emplace_back 接收左值時,實際上的執行效果是先對傳入的引數進行複製構造,然後使用複製構造後的副本,也就是說,emplace_back在接收一個左值的時候其效果和push_back一致!所以在使用emplace_back 時需要確保傳入的引數是一個右值引用,如果不是,請使用std::move()進行轉換

一些庫函式的練習

String

class String
{
    public:
    String(const char* cstr = 0);//建構函式的宣告
    String(const String& str);//構造複製函式
    String& operator=(const String& str);//複製賦值函式
    ~String();
    char* get_c_str() const{return m_data;}//用於cout的函式
    
    private:
    char* m_data;
}

//建構函式
inline //建議作為行內函數,節省空間
String::String(const char* cstr = 0)
{
    if(cstr){
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data , cstr);
    }else{//未指定初值
        m_data = new char[1];
        *m_data = '\0';
    }
}

//解構函式
inline
String::~String()
{
    delete[] m_data; //使用array new所以要用delete array
}

//複製建構函式
inline
String::String(const String& str)
{
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data , str.m_data);
}

//複製賦值函式
inline
String& String::operator(const String& str)
{
    if(this == &str){
        return *this;//自我
    }
    
    delete[] m_data;
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data , str.m_data);
    return *this;
}

STL

體驗STL庫中模板的組成,一個模板可能是由好幾個模板相互疊加而形成的

#include <vector>
#include <algorithm>
#inlcude <functional>
#inlcude <iostream>

using namespace std;

int main(){
    int ia[6] = {27 , 210 , 12 , 47 , 109 , 83};
    vector<int , allocator<int>> vi(ia , ia + 6);//第二個引數可以不寫,因為預設分配
    
    cout<<count_if(vi.begin() , vi.end() , not1(bind2nd(less<int>() , 40)));
    
    
    return 0;
}

STL容器

#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
#include <algorithm>  //sort()
namespace jj02
{
void test_vector(long& value)
{
    cout << "\ntest_vector().......... \n";
      
vector<string> c;     
char buf[10];
             
clock_t timeStart = clock();                                
    for(long i=0; i< value; ++i)
    {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push_back(string(buf));           
        }
        catch(exception& p) {
            cout << "i=" << i << " " << p.what() << endl; 
                 //曾經最高 i=58389486 then std::bad_alloc
            abort();//捕捉到錯誤後及時退出程式
        }
    }
    cout << "milli-seconds : " << (clock()-timeStart) << endl;    
    cout << "vector.max_size()= " << c.max_size() << endl;    //1073747823
    cout << "vector.size()= " << c.size() << endl;        
    cout << "vector.front()= " << c.front() << endl;  
    cout << "vector.back()= " << c.back() << endl;    
    cout << "vector.data()= " << c.data() << endl;
    cout << "vector.capacity()= " << c.capacity() << endl << endl;      
 
                                                                                 
string target = get_a_target_string();
    {
    timeStart = clock();//記錄第一次時間戳
auto pItem = find(c.begin(), c.end(), target);//返回型別為iterator
    cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl;  
      //記錄事件差
    if (pItem != c.end())
        cout << "found, " << *pItem << endl << endl;
    else
        cout << "not found! " << endl << endl;
    }
 
    {
    timeStart = clock();
    sort(c.begin(), c.end());
    cout << "sort(), milli-seconds : " << (clock()-timeStart) << endl; 
     
    timeStart = clock();        
string* pItem = (string*)::bsearch(&target, (c.data()), 
                                   c.size(), sizeof(string), compareStrings); 
    cout << "bsearch(), milli-seconds : " << (clock()-timeStart) << endl; 
        
    if (pItem != NULL)
        cout << "found, " << *pItem << endl << endl;
    else
        cout << "not found! " << endl << endl;    
    }
     
    c.clear();
    test_moveable(vector<MyString>(),vector<MyStrNoMove>(), value); 
}   
}
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <algorithm> //find()
#include <iostream>
#include <ctime> 
namespace jj03
{
void test_list(long& value)
{
    cout << "\ntest_list().......... \n";
      
list<string> c;   
char buf[10];
             
clock_t timeStart = clock();                            
    for(long i=0; i< value; ++i)
    {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push_back(string(buf));       
        }
        catch(exception& p) {
            cout << "i=" << i << " " << p.what() << endl; 
            abort();
        }
    }
    cout << "milli-seconds : " << (clock()-timeStart) << endl;        
    cout << "list.size()= " << c.size() << endl;
    cout << "list.max_size()= " << c.max_size() << endl;    //357913941
    cout << "list.front()= " << c.front() << endl;    
    cout << "list.back()= " << c.back() << endl;      
         
string target = get_a_target_string();      
    timeStart = clock();        
auto pItem = find(c.begin(), c.end(), target);                      
    cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl;       
     
    if (pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found! " << endl;  
         
    timeStart = clock();        
    c.sort();                       
    cout << "c.sort(), milli-seconds : " << (clock()-timeStart) << endl;              
         
    c.clear();
    test_moveable(list<MyString>(),list<MyStrNoMove>(), value);                             
}   
}

相關文章