<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          這些知識(shí)點(diǎn)你都知道嗎,測(cè)試你的C++入門(mén)程度

          共 17887字,需瀏覽 36分鐘

           ·

          2021-05-15 19:46

          公眾號(hào)以來(lái),很多人都私信問(wèn)我如何入門(mén)C++,其實(shí)之前也有很多人問(wèn)過(guò)這個(gè)問(wèn)題,覺(jué)得還是有必要寫(xiě)一篇完整的文章,給大家參考。


          既然要寫(xiě)一篇文章,程序喵本著對(duì)讀者負(fù)責(zé)任的態(tài)度,在寫(xiě)這篇文章前我咨詢(xún)了好多人,既有身經(jīng)百戰(zhàn)的大佬,也有初入職場(chǎng)的精英碼農(nóng),我也查閱了好多入門(mén)C++相關(guān)的資料(發(fā)現(xiàn)內(nèi)容都差不多),結(jié)合自身經(jīng)歷,整理出一篇文章分享給大家。



          不同人入門(mén)C++的方式應(yīng)該都有所不同,就我自己而言,大一先學(xué)習(xí)了C語(yǔ)言,稀里糊涂一個(gè)學(xué)期過(guò)去了,用C語(yǔ)言做個(gè)控制臺(tái)界面的學(xué)生管理系統(tǒng),然后大一下學(xué)期學(xué)習(xí)C++時(shí),恰好上了一門(mén)編譯原理的課,當(dāng)時(shí)實(shí)現(xiàn)了個(gè)小編譯器,做過(guò)校園導(dǎo)航系統(tǒng),小型數(shù)據(jù)庫(kù)系統(tǒng),有點(diǎn)小成就感,原以為算是“C++入門(mén)”了吧?,F(xiàn)在想想其實(shí)很多東西學(xué)生時(shí)期還是知其然而不知其所以然。之后在工作中使用C++做項(xiàng)目,才是真正意義的“入門(mén)”了,所以對(duì)我而言,可能更多的是依靠“實(shí)戰(zhàn)”去入門(mén)的C++。


          本篇文章我不會(huì)全篇介紹入門(mén)C++需要看什么書(shū),看什么視頻,因?yàn)檫@種文章太多了,相信讀者看的已經(jīng)眼花繚亂了,正文主要介紹C++的一些基礎(chǔ)的知識(shí)點(diǎn),基本上對(duì)每個(gè)知識(shí)點(diǎn)我會(huì)貼一段示例代碼,讀者如果要具體了解某個(gè)知識(shí)點(diǎn),可以去文末的書(shū)籍或視頻中針對(duì)性學(xué)習(xí),我會(huì)在文末列出比較容易入門(mén)的幾本書(shū)和視頻。老規(guī)矩,廢話停止,直接開(kāi)始:



          C++是什么?


          通俗的講,可以簡(jiǎn)單理解為C語(yǔ)言的延伸語(yǔ)言,這里會(huì)主要介紹C++相對(duì)于C語(yǔ)言來(lái)說(shuō),有哪些特性。


          C++的一些特點(diǎn):


          允許重載:函數(shù)名相同,參數(shù)類(lèi)型不同,參數(shù)個(gè)數(shù)不同,即可重載,使用見(jiàn)下面代碼:

          // overload.cc#include <iostream>using std::cout;void func(int a) { cout << "func " << a << "\n"; }void func(int a, int b) { cout << "func " << a << " " << b << "\n"; }void func(float a) { cout << "func " << a << "\n"; }int main() {    func(1);    func(1, 2);    func(1.1f);return 0;}

          namespace:namespace是什么?其實(shí)就相當(dāng)于為變量和函數(shù)劃個(gè)范圍


          如果不加namespace會(huì)有什么問(wèn)題:


          // namespace.cc
          #include <iostream>
          void func() { std::cout << "n1 func" << "\n";}
          void func() { std::cout << "n2 func" << "\n";}// redefinition of 'func'int main() { func(); return 0;}


          結(jié)果大家可能都知道,這樣的代碼編譯會(huì)報(bào)錯(cuò):redefinition of 'func'


          一般規(guī)定一個(gè)程序內(nèi)不允許同一個(gè)強(qiáng)符號(hào)有多個(gè)定義,那怎么解決?


          可使用namespace:

          // namespace.cc
          #include <iostream>
          namespace n1 {
          void func() { std::cout << "n1 func" << "\n";}
          } // namespace n1
          namespace n2 {
          void func() { std::cout << "n2 func" << "\n";}
          } // namespace n2
          // redefinition of 'func'
          int main() { n1::func(); n2::func(); return 0;}


          這樣編譯成功,加入namespace后其實(shí)對(duì)編譯器來(lái)說(shuō)就是兩個(gè)不同的函數(shù),因?yàn)樯傻氖莾蓚€(gè)不同的符號(hào):



          注意:不要過(guò)多using namespace xxx,例如using namespace std;可能就容易引起符號(hào)沖突問(wèn)題,


          可以使用using std::cout這種方式。


          class & struct

          很多面試官可能都會(huì)問(wèn)class和struct的區(qū)別?具體答案我這里就不貼出來(lái)了,大家自己搜索答案就可,或者留言問(wèn)我,它倆在C++里其實(shí)沒(méi)什么區(qū)別,就是默認(rèn)權(quán)限不同而已。


          這里需要掌握幾個(gè)知識(shí)點(diǎn):

          • 如何定義一個(gè)類(lèi)

          • 構(gòu)造函數(shù)的定義及使用

          • 析構(gòu)函數(shù)的定義及使用

          • 拷貝構(gòu)造函數(shù)的定義及使用

          • 移動(dòng)構(gòu)造函數(shù)的定義及使用

          • 賦值構(gòu)造函數(shù)的定義及使用

          • 移動(dòng)賦值函數(shù)的定義及使用


          下面貼出一段示例代碼:

          // class.cc#include <iostream>#include <memory>
          using std::cout;
          class TClass { public: TClass() { cout << "構(gòu)造函數(shù)1" << "\n"; }
          TClass(int a) : a_(a) { cout << "構(gòu)造函數(shù)2" << "\n"; data_ = new int[10]; }
          TClass(const TClass &a) : a_(a.a_) { cout << "拷貝構(gòu)造函數(shù)" << "\n"; data_ = new int[10];
          memcpy(data_, a.data_, 10 * sizeof(int)); }
          TClass(TClass &&a) : a_(a.a_), data_(a.data_) { a.data_ = nullptr; cout << "移動(dòng)構(gòu)造函數(shù)" << "\n"; }
          TClass &operator=(TClass &a) { a_ = a.a_; if (data_) delete[] data_; data_ = new int[10]; memcpy(data_, a.data_, 10 * sizeof(int));
          cout << "賦值構(gòu)造函數(shù)" << "\n"; return *this; }
          TClass &operator=(TClass &&a) { a_ = a.a_; if (data_) delete[] data_; data_ = a.data_; a.data_ = nullptr; cout << "移動(dòng)賦值函數(shù)" << "\n"; return *this; }
          ~TClass() { cout << "析構(gòu)函數(shù)" << "\n"; if (data_) delete[] data_; }
          void func() { cout << "a " << a_ << " \n"; }
          private: int a_; int *data_;};
          int main() { TClass a(1); //構(gòu)造函數(shù)2 TClass b(a); //拷貝構(gòu)造函數(shù) TClass c(std::move(a)); //移動(dòng)構(gòu)造函數(shù) c = b; //賦值構(gòu)造函數(shù) c = std::move(b); //移動(dòng)賦值函數(shù) TClass d = c; //拷貝構(gòu)造函數(shù) TClass e = std::move(d); //移動(dòng)構(gòu)造函數(shù) a.func(); b.func(); return 0;}


          模板

          模板主要分為函數(shù)模板類(lèi)模板,下面有示例代碼:

          // template.cc#include <iostream>
          using std::cout;template <typename T>T max(T a, T b) { // 函數(shù)模板 return a > b ? a : b;}
          template <typename T>struct Vec { // 類(lèi)模板 Vec(T a) : a_(a) {}
          void func() { cout << "func value " << a_ << "\n"; } T a_;};
          int main() { cout << "max(1, 2) " << max(1, 2) << "\n"; cout << "max(1.1f, 2.2f) " << max(1.1f, 2.2f) << "\n"; cout << "max(1.10, 2.20) " << max(1.10, 2.20) << "\n";
          Vec<int> vi(1); vi.func();
          Vec<float> vf(1.1f); vf.func(); return 0;}


          引用:C++里多了個(gè)引用的概念,很多人面試應(yīng)該有被問(wèn)到過(guò)引用和指針有什么區(qū)別吧?


          關(guān)于指針和引用,在這里強(qiáng)烈推薦大家閱讀《面試系列之指針和引用的使用場(chǎng)景》這篇文章,通俗易懂的純干貨型文章。


          大家可以記住一個(gè)關(guān)鍵點(diǎn)就是引用追求從一而終,它的指向永遠(yuǎn)不會(huì)變,而指針是個(gè)善變的東西,它的指向隨時(shí)可以改變,一般開(kāi)發(fā)中會(huì)使用const &方式進(jìn)行參數(shù)傳遞,省去不必要的對(duì)象拷貝:


          void func(const A& a) {}


          多態(tài):這是C++語(yǔ)言所支持的或者說(shuō)面向?qū)ο蟮囊粋€(gè)重要特性,直接看代碼:


          // polymorphic.cc
          #include <iostream>using std::cout;struct Base { Base() { cout << "base construct" << "\n"; }
          virtual ~Base() { cout << "base destruct" << "\n"; }
          void FuncA() {}
          virtual void FuncB() { cout << "Base FuncB \n"; }
          int a; int b;};
          struct Derive1 : public Base { Derive1() { cout << "Derive1 construct \n"; } ~Derive1() { cout << "Derive1 destruct \n"; } void FuncB() override { cout << "Derive1 FuncB \n"; }};
          struct Derive2 : public Base { Derive2() { cout << "Derive2 construct \n"; } ~Derive2() { cout << "Derive2 destruct \n"; } void FuncB() override { cout << "Derive2 FuncB \n"; }};

          int main() { { Derive1 d1; d1.FuncB(); }
          cout << "======= \n"; { Derive1 d1; d1.FuncB();
          Base &b1 = d1; b1.FuncB(); }
          cout << "======= \n"; { Derive2 d2; d2.FuncB();
          Base &b2 = d2; b2.FuncB(); }
          cout << "======= \n"; { Base b; b.FuncB(); }
          cout << "======= \n"; { Base *b = new Derive1(); b->FuncB(); delete b; }
          return 0;}


          這里簡(jiǎn)單介紹了實(shí)現(xiàn)多態(tài)的兩種方式:通過(guò)指針或者通過(guò)引用。


          注意:

          • 構(gòu)造函數(shù)不能是虛函數(shù)

          • 基類(lèi)析構(gòu)函數(shù)最好是虛函數(shù)

          • 盡量不要使用多繼承


          new和delete


          C++內(nèi)存申請(qǐng)和釋放會(huì)使用new和delete關(guān)鍵字,而基本不會(huì)使用C語(yǔ)言中的malloc和free,可看下面的示例代碼:

          // new_delete.cc
          #include <iostream>
          using std::cout;
          struct A { int a_;};
          int main() { A* a1 = new A; delete a1;
          A* a2 = new A[10]; delete[] a2; return 0;}


          注意:

          • new和delete要配對(duì)使用

          • new[]和delete[]要配對(duì)使用

          • maloc和free要配對(duì)使用


          類(lèi)型轉(zhuǎn)換:既然使用了C++語(yǔ)言,在類(lèi)型轉(zhuǎn)換方面就一定要使用C++風(fēng)格,這比C語(yǔ)言風(fēng)格的強(qiáng)制類(lèi)型轉(zhuǎn)換更安全。


          • static_cast

          float f = 1.0f;int a = static_cast<int>(f);


          • const_cast

          const char* cc = "hello world\n";char* c = const_cast<char*>(cc);


          • dynamic_cast

          struct Base {};struct Derive : public Base {};void func() {    Base* base = new Derive;    Derive* derive = dynamic_cast<Derive*>(base);}


          • reinterpret_cast

          A *a = new A;void* d = reinterpret_cast<void*>(a);


          C++11常用新特性


          C++的重大變革肯定是C++11啦,C++11標(biāo)準(zhǔn)引入了很多有用的新特性,這仿佛打開(kāi)了新世界的大門(mén),讓C++開(kāi)發(fā)者開(kāi)發(fā)效率大幅提高,下面我會(huì)列出C++11常用的新特性,并附上簡(jiǎn)單的實(shí)例代碼:


          auto & decltype:用于類(lèi)型推導(dǎo)


          auto用于推導(dǎo)變量類(lèi)型,decltype用于推導(dǎo)表達(dá)式返回值類(lèi)型

          // auto_decltype.cc
          int main() { auto a = 10; // 10是int型,可以自動(dòng)推導(dǎo)出a是int
          int x = 0; decltype(x) y; // y是int類(lèi)型 decltype(x + y) z; // z是int類(lèi)型
          return 0;}


          std::function:用于封裝一個(gè)函數(shù),功能類(lèi)似于函數(shù)指針,但卻比函數(shù)指針?lè)奖愕亩唷?/span>

          // function.cc
          #include <functional>#include <iostream>
          using std::cout;
          void printNum(int i) { cout << "print num " << i << "\n"; }
          typedef void (*FuncPtr)(int i);
          int main() { FuncPtr ptr = printNum; ptr(2);
          void (*ptr2)(int) = printNum; ptr2(3);
          std::function<void(int)> func = printNum; func(1);
          return 0;}


          lambda表達(dá)式:隨時(shí)可方便定義的一個(gè)匿名函數(shù)。

          // lambda.cc#include <iostream>using std::cout;
          int main() { auto func = [](int a) -> int { return a + 1; }; int b = func(2); cout << b << "\n"; return 0;}


          注意:lambda表達(dá)式的變量捕獲方式分為值捕獲和引用捕獲

          int a = 0;auto f1 = [=](){ return a; }; // 值捕獲acout << f1() << endl;
          auto f2 = [=]() { return a++; }; // 修改按值捕獲的外部變量,errorauto f3 = [=]() mutable { return a++; };

          std::function和std::bind使得我們平時(shí)編程過(guò)程中封裝函數(shù)更加的方便,而lambda表達(dá)式將這種方便發(fā)揮到了極致,可以在需要的時(shí)間就地定義匿名函數(shù),不再需要定義類(lèi)或者函數(shù)等,在自定義STL規(guī)則時(shí)候也非常方便,讓代碼更簡(jiǎn)潔,更靈活,開(kāi)發(fā)效率也更高。


          std::thread:C++11中使用std::thread創(chuàng)建線程,使用非常的方便,直接看代碼:

          void func() { std::cout << "new thread \n"; }int main() {    std::thread t(func);    if (t.joinable()) {        t.join(); // 或者t.detach();     }    return 0;}

          注意:使用std::thread一定要記得join或者detach。


          RAII:既然使用C++,那一定要理解RAII風(fēng)格(利用對(duì)象生命周期管理資源),繼續(xù)往下看:


          如果不使用RAII風(fēng)格,加鎖解鎖我們?cè)趺崔k?

          // 不使用RAIIvoid func() {    std::mutex mutex;    mutex.lock();    if (xxx) {        mutex.unlock();        return;    }    if (xxxx) {        mutex.unlock();        return;    }    ...    mutex.unlock();}


          而如果使用RAII呢:

          void func() {    std::unique_lock<std::mutex> lock(mutex);    if (xxx) return;    if (xxxx) return;    ...}


          是不是方便了很多,這里介紹了std::unique_lock的使用,還有一種鎖是std::lock_guard,使用方式相同,至于它們之間有什么區(qū)別,我這里賣(mài)個(gè)關(guān)子,大家可以自行查找哈,鍛煉一下自己的搜索能力。


          智能指針也是典型的RAII風(fēng)格,如果不使用智能指針管理內(nèi)存是這樣:

          void func() {    A* a = new A;    if (xxx) {        delete a;        return;    }    if (xxxx) {        delete a;        return;    }    ...    delete a;}


          而如果使用智能指針是這樣:

          void func() {    std::shared_ptr<A> sp = std::make_shared<A>(); // unique_ptr類(lèi)似    std::shared_ptr<A> sp = std::shared_ptr<A>(new A); // 盡可能使用make_shared或者make_unique(C++14)    if (xxx) return;    if (xxxx) return;    ...}


          又方便了很多吧,unique_ptr和shared_ptr的區(qū)別本文也不介紹,文章最后我會(huì)列出學(xué)習(xí)資料,在學(xué)習(xí)資料里可以找到答案。


          原子操作:使用std::atomic可達(dá)到原子效果,使用方法:

          std::atomic<int> ai;ai++;ai.store(100);int a = ai.load();


          enum class:帶有作用域的枚舉類(lèi)型,可用于完全替代enum,為什么要使用enum class呢?我們先看一段直接使用enum的代碼:

          enum AColor {    kRed,    kGreen,    kBlue};
          enum BColor { kWhite, kBlack, kYellow};
          int main() { if (kRed == kWhite) { cout << "red == white" << endl; } return 0;}


          不帶作用域的枚舉類(lèi)型可以自動(dòng)轉(zhuǎn)換成整形,且不同的枚舉可以相互比較,代碼中的kRed居然可以和kWhite比較,這都是潛在的難以調(diào)試的bug,而這種完全可以通過(guò)有作用域的枚舉來(lái)規(guī)避。


          所以出現(xiàn)了enum class:

          enum class AColor {    kRed,    kGreen,    kBlue};
          enum class BColor { kWhite, kBlack, kYellow};
          int main() { if (AColor::kRed == BColor::kWhite) { // 編譯失敗 cout << "red == white" << endl; } return 0;}


          使用enum class可以在編譯層面就規(guī)避掉一些難以調(diào)試的bug,使代碼健壯性更高。


          condition_variable:條件變量

          std::condition_variable cv;std::mutex mutex_;void func1() {    std::unique_lock<std::mutex> lock(mutex_);    --count;    if (count == 0) cv.notify_all();}void func2() {    std::unique_lock<std::mutex> lock(mutex_);    while (count) {        cv.wait(lock);    }}

          注意:不要直接用wait,而要記得使用wait(mutex, cond)或者while(cond) {wait(mutex);}


          nullptr:表示空指針可以使用nullptr,不要使用NULL

          void func(char*) {    cout << "char*";}void func(int) {    cout << "int";}
          int main() { func(NULL); // 編譯失敗 error: call of overloaded ‘func(NULL)’ is ambiguous func(nullptr); // char* return 0;}


          chrono:時(shí)間相關(guān)函數(shù)可以考慮使用chrono庫(kù),例如休眠某個(gè)時(shí)間段:

          void customSleep() {    std::this_thread::sleep_for(std::chrono::milliseconds(5));    std::this_thread::sleep_for(std::chrono::seconds(5));}


          使用chrono可以精確的指定時(shí)間單位,可以明確的之道休眠的是幾毫秒還是幾秒,非常方便。


          chrono中包含三種時(shí)鐘:

          • steady_clock:?jiǎn)握{(diào)時(shí)鐘,只會(huì)增加,常用語(yǔ)記錄程序耗時(shí)

          • system_clock:系統(tǒng)時(shí)鐘,會(huì)隨系統(tǒng)時(shí)間改動(dòng)而變化

          • high_resolution_clock:當(dāng)前系統(tǒng)最高精度的時(shí)鐘,通常就是steady_clock


          拿計(jì)時(shí)舉例:

          void customSleep() {    std::this_thread::sleep_for(std::chrono::milliseconds(5));    std::this_thread::sleep_for(std::chrono::seconds(5));}
          int main() { std::chrono::time_point<std::chrono::high_resolution_clock> begin = std::chrono::high_resolution_clock::now(); customSleep(); auto end = std::chrono::high_resolution_clock::now(); auto diff = end - begin; long long diffCount = std::chrono::duration_cast<std::chrono::milliseconds>(diff).count(); cout << diffCount << "\n";
          return 0;}


          STL


          使用C++有幾個(gè)能不用STL標(biāo)準(zhǔn)庫(kù)的,這里列出了常用的STL,并貼出使用代碼。


          std::vector:可以理解為動(dòng)態(tài)可自動(dòng)擴(kuò)容的數(shù)組,使用vector需要掌握幾個(gè)常用函數(shù)的使用

          • resize

          • reserve

          • capacity

          • clear

          • swap

          • at


          靈活使用

          void func() {    std::vector<int> vec;    std::cout << "vector size " << vec.size() << "\n";          // vector size 0    std::cout << "vector capacity " << vec.capacity() << "\n";  // vector capacity 0    vec.push_back(1);    vec.emplace_back(2);    vec.push_back(3);    std::cout << "====================== \n";    std::cout << "vector size " << vec.size() << "\n";          // vector size 3    std::cout << "vector capacity " << vec.capacity() << "\n";  // vector capacity 4    vec.reserve(200);    std::cout << "====================== \n";    std::cout << "vector size " << vec.size() << "\n";          // vector size 3    std::cout << "vector capacity " << vec.capacity() << "\n";  // vector capacity 200    vec.resize(20);    std::cout << "====================== \n";    std::cout << "vector size " << vec.size() << "\n";          // vector size 20    std::cout << "vector capacity " << vec.capacity() << "\n";  // vector capacity 200    vec.clear();    std::cout << "====================== \n";    std::cout << "vector size " << vec.size() << "\n";          // vector size 0    std::cout << "vector capacity " << vec.capacity() << "\n";  // vector capacity 200    std::vector<int>().swap(vec);    std::cout << "====================== \n";    std::cout << "vector size " << vec.size() << "\n";          // vector size 0    std::cout << "vector capacity " << vec.capacity() << "\n";  // vector capacity 0}


          注意:for循環(huán)中erase某一個(gè)節(jié)點(diǎn)時(shí)要處理好迭代器的指向問(wèn)題

          void erase(std::vector<int> &vec, int a) {    for (auto iter = vec.begin(); iter != vec.end();) { // 正確        if (*iter == a) {            iter = vec.erase(iter);        } else {            ++iter;        }    }
          for (auto iter = vec.begin(); iter != vec.end(); ++iter) { // error if (*iter == a) { vec.erase(iter); } }}


          繼續(xù)注意:remove函數(shù)不會(huì)真正的刪除某個(gè)元素,它只會(huì)把某個(gè)要?jiǎng)h除的元素移動(dòng)到容器尾部,真正要?jiǎng)h除還需使用erase,需要remove要和erase搭配使用。

          bool isOdd(int i) { return i & 1; }
          void print(const std::vector<int>& vec) { for (const auto& i : vec) { std::cout << i << ' '; } std::cout << std::endl;}
          int main() { std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; print(v);
          std::remove(v.begin(), v.end(), 5); // error print(v);
          v.erase(std::remove(v.begin(), v.end(), 5), v.end()); print(v);
          v.erase(std::remove_if(v.begin(), v.end(), isOdd), v.end()); print(v);}


          std::array:開(kāi)發(fā)時(shí)可以考慮用std::array代替普通數(shù)組,因?yàn)樗蝎@取長(zhǎng)度,遍歷,邊界檢查等功能

          int main() {    std::array<int, 10> array;    // int array[10];    array.at(10) = 20;  // terminating with uncaught exception of type std::out_of_range: array::at    std::cout << "hello " << array.at(10) << "\n";    return 0;}


          std::map & std::unordered_map:都是key-value級(jí)別的字典,使用方式相同,一個(gè)使用樹(shù)實(shí)現(xiàn),一個(gè)使用哈希表實(shí)現(xiàn),可根據(jù)需求選擇具體使用哪種字典。

          int main() {    std::map<int, std::string> map;    map[1] = std::string("hello");    std::cout << map[1] << "\n";    return 0;}


          std::list:鏈表

          int main() {    std::list<int> list{1, 2, 3, 2};    list.sort();    // std::sort(list.begin(), list.end());    for (auto i : list) {        std::cout << i << " ";    }    std::cout << "\n";    return 0;}


          注意:list的排序需要使用list.sort(),不能使用std::sort


          std::tuple:我個(gè)人經(jīng)常使用,tuple像結(jié)構(gòu)體一樣,也可以理解為pair的延伸

          struct T {    int a_;    int b_;    int c_;    T(int a, int b, int c) : a_(a), b_(b), c_(c) {}};
          int main() { T a(1, 2, 3); std::cout << "a " << a.a_ << " b " << a.b_ << " c " << a.c_ << "\n"; std::tuple<int, int, int> tuple = std::make_tuple(2, 3, 4); std::cout << "a " << std::get<0>(tuple) << " b " << std::get<1>(tuple) << " c " << std::get<2>(tuple) << "\n"; return 0;}


          編碼規(guī)范


          每一門(mén)語(yǔ)言基本都有幾種常見(jiàn)的編碼規(guī)范,想必大多數(shù)C++開(kāi)發(fā)者都會(huì)基于google的C++編碼規(guī)范去開(kāi)發(fā),下面是格式化代碼常用的一些配置:

          // .clang-formatBasedOnStyle: GoogleIndentWidth: 4ColumnLimit: 120SortIncludes: trueMaxEmptyLinesToKeep: 2


          下面再列出一些常見(jiàn)的命名規(guī)則:


          文件命名:文件名字要全部小寫(xiě),中間用_相連,后綴名為.cc .cpp和.h

          hello_world.cchello_world.cpphello_world.h


          類(lèi)型命名:類(lèi)型名稱(chēng)的每個(gè)單詞首字母均大寫(xiě):

          struct MyExcitingClass;


          常量和枚舉命名:聲明為 constexpr 或 const 的變量, 或在程序運(yùn)行期間其值始終保持不變的, 命名時(shí)以 “k” 開(kāi)頭, 大小寫(xiě)混合

          const int kDaysInAWeek = 7;


          函數(shù)命名:大駝峰方式

          MyExcitingFunction()


          命名空間命名:全部小寫(xiě)

          namespace abcdefg{}


          成員變量命名:小寫(xiě)字母加下劃線分隔,最后加個(gè)下劃線


          普通變量命名:小寫(xiě)字母加下劃線分隔

          struct A {    int a_;}void f(int a) {    int b;}


          代碼:

          struct A {    int a_;}void f(int a) {    int b;}


          規(guī)范要點(diǎn)總結(jié)


          下面是我查閱很多資料又結(jié)合自身工作經(jīng)驗(yàn)總結(jié)的一些要點(diǎn):

          • 每個(gè)頭文件都要使用#ifndef #define或者#pragma once修飾,避免被重復(fù)引用

          • 每個(gè)命名都要盡可能表達(dá)清晰其具體含義,除非特別常用,否則不要使用縮寫(xiě),寧可名字特別長(zhǎng)

          • 鼓勵(lì)在 .cc 文件內(nèi)使用匿名命名空間或 static 聲明. 使用具名的命名空間時(shí), 其名稱(chēng)可基于項(xiàng)目名或相對(duì)路徑. 盡量不要使用 using 指示

          • 一行盡量不要超過(guò)120個(gè)字符,一個(gè)函數(shù)盡量不要超過(guò)40行(性能優(yōu)化除外),同時(shí)一個(gè)文件盡量控制在500行內(nèi).

          • 所有的引用形參如不做改動(dòng)一律加const,在任何可能的情況下都要使用 const或constexpr

          • new內(nèi)存的地方盡量使用智能指針,c++11 就盡量用std::unique_ptr

          • 合理使用移動(dòng)語(yǔ)義或者COW,減少內(nèi)存拷貝

          • 使用 C++ 的類(lèi)型轉(zhuǎn)換, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等轉(zhuǎn)換方式

          • 明確使用前置++還是后置++的具體含義,如不考慮返回值,盡量使用前置++ (++i)

          • 不要使用uint類(lèi)型,如果需要使用大整型可以考慮int64,否則類(lèi)型的隱式類(lèi)型轉(zhuǎn)換會(huì)帶來(lái)很多麻煩

          • 如無(wú)特殊必要不要使用宏,可以考慮使用const或constexpr替代宏,宏的全局作用域很麻煩,如果非要用在馬上要使用時(shí)才進(jìn)行 #define, 使用后要立即 #undef

          • 盡可能用 sizeof(varname) 代替 sizeof(type).使用 sizeof(varname) 是因?yàn)楫?dāng)代碼中變量類(lèi)型改變時(shí)會(huì)自動(dòng)更新. 或許會(huì)用 sizeof(type) 處理不涉及任何變量的代碼,比如處理來(lái)自外部或內(nèi)部的數(shù)據(jù)格式,這時(shí)用變量就不合適了

          • 類(lèi)型名如果過(guò)長(zhǎng)的話可以考慮使用auto關(guān)鍵字

          • 注釋統(tǒng)一使用 // ,不要通過(guò)注釋禁用代碼,擅用git,不要為易懂的代碼寫(xiě)注釋

          • 寫(xiě)完代碼后記得format,每個(gè)項(xiàng)目最好都有統(tǒng)一的.clang_format文件

          • 使用C++的string替代C語(yǔ)言風(fēng)格的char*

          • 盡量使用STL標(biāo)準(zhǔn)庫(kù)的容器而不是C語(yǔ)言風(fēng)格的數(shù)組,數(shù)組的越界訪問(wèn)之類(lèi)當(dāng)時(shí)是不會(huì)報(bào)錯(cuò)的,反而可能弄臟堆棧信息,導(dǎo)致奇奇怪怪難以排查的bug

          • 可以更多的使用模板元編程,盡量多的使用constexpr等編譯期計(jì)算,編譯器是我們的好搭檔,個(gè)人認(rèn)為模板元編程以后會(huì)是C++的主流技術(shù)

          • 可以考慮更多的使用異常處理方式,而不是C語(yǔ)言風(fēng)格的errno錯(cuò)誤碼等

          • 常用大括號(hào)控制生命周期,能提前結(jié)束的就可以提前結(jié)束

          • 注意memcpy和memset的使用,僅適用于POD結(jié)構(gòu)

          • 理解內(nèi)存對(duì)齊,可以使結(jié)構(gòu)體更小,也可以使訪問(wèn)速度更快

          • 基類(lèi)析構(gòu)函數(shù)一定要加virtual修飾

          • 謹(jǐn)慎使用多繼承,可能導(dǎo)致菱形繼承

          • 全局變量不要有任何依賴(lài)關(guān)系


          這里我只列出來(lái)兩本學(xué)習(xí)C++的書(shū),可以按順序閱讀,我相信讀完并理解這兩本書(shū)的內(nèi)容可以算是入門(mén)C++啦~


          書(shū)


          《C++ Primer Plus》 注意是Plus!

          《Effective Modern C++》


          視頻


          有喜歡看書(shū)的也有喜歡看視頻的,這里再推薦兩個(gè)比較好的C++視頻教程:


          ①清華大學(xué)鄭莉教授的視頻,通俗易懂

          https://www.bilibili.com/video/BV1QE41147RT?from=search&seid=8449657388898463710


          還有一個(gè)是技術(shù)交流群群友推薦,也是清華大學(xué)的課程

          https://www.bilibili.com/video/BV1yk4y1d7ns?p=1


          喜歡英文的同學(xué)可以看看MIT或斯坦福的C++課程


          具體是看書(shū)快還是看視頻快,因人而異。適合自己的才是最實(shí)在、最好的。


          再推薦兩個(gè)比較好的C++學(xué)習(xí)網(wǎng)站


          最好的肯定是cppreference啦,不用多說(shuō),也可以看看cppfaq,里面的很多問(wèn)題可以增長(zhǎng)我們的見(jiàn)識(shí),讓我們對(duì)C++的理解也更加深刻。


          http://www.sunistudio.com/cppfaq/



          C++學(xué)習(xí)資料免費(fèi)獲取方法:關(guān)注程序喵大人,后臺(tái)回復(fù)“程序喵”即可免費(fèi)獲取40萬(wàn)字C++進(jìn)階獨(dú)家學(xué)習(xí)資料。

          瀏覽 48
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  美女脱光色情视频网站亚洲 | 日美三级片 | 亚洲熟女成人AV | 91女人18毛片水多国产 | 粉嫩小泬无遮挡BBBB |