本期是C++基礎語法分享的第六節,今天給大家來分享一下:
(1)引用;
(2)宏;
(3)成員初始化列表;
(4)封裝;
(5)繼承;
(6)多型;
引用
左值引用
常規引用,一般表示物件的身份。
右值引用
右值引用就是必須繫結到右值(一個臨時物件、將要銷燬的物件)的引用,一般表示物件的值。
右值引用可實現轉移語義(Move Sementics)和精確傳遞(Perfect Forwarding),它的主要目的有兩個方面:
消除兩個物件互動時不必要的物件複製,節省運算儲存資源,提高效率。
能夠更簡潔明確地定義泛型函式。
引用摺疊
X& &、X& &&、X&& & 可摺疊成 X&
X&& && 可摺疊成 X&&
宏
宏定義可以實現類似於函式的功能,但是它終歸不是函式,而宏定義中括弧中的“引數”也不是真的引數,在宏展開的時候對 “引數” 進行的是一對一的替換。
成員初始化列表
好處
更高效:少了一次呼叫預設建構函式的過程。
有些場合必須要用初始化列表:
常量成員,因為常量只能初始化不能賦值,所以必須放在初始化列表裡面
引用型別,引用必須在定義的時候初始化,並且不能重新賦值,所以也要寫在初始化列表裡面
沒有預設建構函式的類型別,因為使用初始化列表可以不必呼叫預設建構函式來初始化
initializer_list 列表初始化
用花括號初始化器列表初始化一個物件,其中對應建構函式接受一個 std::initializer_list 引數.
initializer_list 使用
#include <iostream>#include <vector>#include <initializer_list> template <class T>struct S { std::vector<T> v; S(std::initializer_list<T> l) : v(l) { std::cout << "constructed with a " << l.size() << "-element list\n"; } void append(std::initializer_list<T> l) { v.insert(v.end(), l.begin(), l.end()); } std::pair<const T*, std::size_t> c_arr() const { return {&v[0], v.size()}; // 在 return 語句中複製列表初始化 // 這不使用 std::initializer_list }}; template <typename T>void templated_fn(T) {} int main(){ S<int> s = {1, 2, 3, 4, 5}; // 複製初始化 s.append({6, 7, 8}); // 函式呼叫中的列表初始化 std::cout << "The vector size is now " << s.c_arr().second << " ints:\n"; for (auto n : s.v) std::cout << n << ' '; std::cout << '\n'; std::cout << "Range-for over brace-init-list: \n"; for (int x : {-1, -2, -3}) // auto 的規則令此帶範圍 for 工作 std::cout << x << ' '; std::cout << '\n'; auto al = {10, 11, 12}; // auto 的特殊規則 std::cout << "The list bound to auto has size() = " << al.size() << '\n'; // templated_fn({1, 2, 3}); // 編譯錯誤!“ {1, 2, 3} ”不是表示式, // 它無型別,故 T 無法推導 templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK templated_fn<std::vector<int>>({1, 2, 3}); // 也 OK}
面向物件
面向物件程式設計(Object-oriented programming,OOP)是種具有物件概念的程式程式設計典範,同時也是一種程式開發的抽象方針。
面向物件三大特徵 —— 封裝、繼承、多型
封裝
把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏。關鍵字:public, protected, private。不寫預設為 private。
public 成員:可以被任意實體訪問
protected 成員:只允許被子類及本類的成員函式訪問
private 成員:只允許被本類的成員函式、友元類或友元函式訪問
繼承
基類(父類)——> 派生類(子類)
多型
多型,即多種狀態(形態)。簡單來說,我們可以將多型定義為訊息以多種形式顯示的能力。
多型是以封裝和繼承為基礎的。
C++ 多型分類及實現:
過載多型(Ad-hoc Polymorphism,編譯期):函式過載、運算子過載
子型別多型(Subtype Polymorphism,執行期):虛擬函式
引數多型性(Parametric Polymorphism,編譯期):類模板、函式模板
強制多型(Coercion Polymorphism,編譯期/執行期):基本型別轉換、自定義型別轉換
靜態多型(編譯期/早繫結)
函式過載
class A{public: void do(int a); void do(int a, int b);};
動態多型(執行期期/晚繫結)
虛擬函式:用 virtual 修飾成員函式,使其成為虛擬函式
動態繫結:當使用基類的引用或指標呼叫一個虛擬函式時將發生動態繫結
注意:
可以將派生類的物件賦值給基類的指標或引用,反之不可
普通函式(非類成員函式)不能是虛擬函式
靜態函式(static)不能是虛擬函式
建構函式不能是虛擬函式(因為在呼叫建構函式時,虛表指標並沒有在物件的記憶體空間中,必須要建構函式呼叫完成後才會形成虛表指標)
行內函數不能是表現多型性時的虛擬函式
動態多型使用
class Shape // 形狀類{public: virtual double calcArea() { ... } virtual ~Shape();};class Circle : public Shape // 圓形類{public: virtual double calcArea(); ...};class Rect : public Shape // 矩形類{public: virtual double calcArea(); ...};int main(){ Shape * shape1 = new Circle(4.0); Shape * shape2 = new Rect(5.0, 6.0); shape1->calcArea(); // 呼叫圓形類裡面的方法 shape2->calcArea(); // 呼叫矩形類裡面的方法 delete shape1; shape1 = nullptr; delete shape2; shape2 = nullptr; return 0;}
今天的分享就到這裡了,大家要好好學C++喲~
寫在最後:對於準備學習C/C++程式設計的小夥伴,如果你想更好的提升你的程式設計核心能力(內功)不妨從現在開始!
程式設計學習書籍分享:
程式設計學習影片分享:
整理分享(多年學習的原始碼、專案實戰影片、專案筆記,基礎入門教程)