C++ Primer(英語第5版) 閱讀日記 - 20201222

liubai01發表於2020-12-22

前言

有生之年系列。上次更新是4月份,咕咕咕了8個月了。C++ Primer還是得系統讀完一次。
依舊重複一點:這不是一份涵蓋每個細節的筆記,使一份強調一些基本概念的精準表述,和一些常見混淆概念的記錄。為的是讓類似我這種平日憑經驗寫C++的人,走向更系統的對C++的理解。

2.5 Dealing with Types

A type alias(型別別名) is a name that is a synonym(同義替代) for another type.

typedef double wages;
typedef wages base, *p; // base 是double的同義詞,p是double*的同義詞

(c++11) using alias新操作:

using SI = Sales_item;

指標+別名+const 混合

注意的是,const放在指標中,常用來限定指向的物件為常量。但是,當使用別名的時候。
我們應該概念上代入,而不是使用字元替換。看下面這個書本給的例子:

typedef char *pstring;
const pstring cstr = 0; // cstr是常量指標,指向char
const pstring *ps; // cstr是指標,指向常量指標,再指向char。

注意到const pstring如果我們把char *帶入 應該是 const char *,也就是指向常量char的指標,而非是常量指標,指向char。
這也就意味著概念上,我們將char *,也就是char指標認為是一個整體,而不是簡單地對原始碼進行字元替換。

2.5.2 auto 指標

使用auto type specifier,編譯器就會自動推斷型別。

  • 當我們使用引用(reference)作為intializer時,編譯器使用對應object的型別(而非引用)作為auto的型別推斷。
  • top-level const 在使用auto時會被丟棄
  • 如果需要定義auto的引用或者const的auto,我們需要顯式定義
const int ci = i;
auto b = ci; // b is an int instead of const int
const auto f = ci; // f is a const int
auto auto &j = 42; // have a const reference to a literal

2.5.3 The decltype Type Specifier

當我們想從一個表示式推斷出型別的時候,我們可以使用decltype:個人推斷是declare type的縮寫。

decltype(f()) sum = x;

f沒有實際上被呼叫,但是我們定義了sum為f函式返回的型別。
decltype和auto不同,當decltype標的是變數時,我們保留top-level的const和reference。

const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x has type const int
decltype(cj) y = x; // y has type const int& and is bound to x
decltype(cj) z; // error: z is a reference and must be initialized

同時,通常來說,當decltype用在expression時,就要看錶達式返回的是什麼。以下兩點注意:

  • + 加號返回的是nonreference type
  • * 星號作為解引用符號時,返回的是reference
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // ok: 加號返回int
decltype(*p) c; // error: c是int的reference

以下有種奇怪的括號(parenthesis)特殊情況:

decltype((i)) d; // error: d是引用,必須被初始化
decltype(i) e; // ok

被括號括起來時,decltype就認為是一個引用了。這很tricky。

2.6 Defining Our Own Data Structures

**資料結構體(sturcture)**是一種組織相關資料的方式。我們通過定義class來定義我們自己的資料型別。

  • The class body defines the members of the class.
  • Each object has its own copy of the class data members.
  • Modifying the data members of one object does not change the data in any other object.

2.6.2 Preprocessor

**Preprocessor(前處理器)**是C++從C這繼承來的。在編譯器(compiler)之前,前處理器通過修改原始碼文字。

  • 當前處理器看到#include,就會使用include對應標頭檔案的內容去替換文字。
  • 標頭檔案保護符(header guards)依賴於前處理器變數(preprocessor variables),擁有兩種狀態:define or not defined。
    • #define 指令(directive)定義前處理器變數
    • #ifdef <var>指令值為true如果該變數被定義。#ifndef <var>指令指為true如果該變數未被定義。#endif為結束標誌。

為了避免重複定義(multiple inclusion),我們可以使用header guards。這是很常見的使用,絕大多數程式都可以看到。

#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
struct Sales_data {
 std::string bookNo; unsigned units_sold = 0; double revenue = 0.0;
};
#endif

Namespace using Declarations

A using declaration lets us use a name from a namespace without qualifying the name with a namespace_name:: prefix. A using declaration has the form.
標頭檔案不用應該包含using: 因為標頭檔案會被前處理器拷貝入程式文字。在標頭檔案的using可能會發生衝突(conflicts)。

3.2 Library string Type

關於字串string的使用細節,本篇筆記不做全部的記錄。在這裡,我只記錄一下我認為會遺忘並有價值復看的內容。
常見初始化方式

string s1; // an empty string
string s2 = s1; // s2 is a copy of s1
string s3 = "hiya"; // s3 is a copy of the string literal
string s4(10, 'c'); // s4 is cccccccccc

當我們通過"=“初始化一個變數時,我們要求 compiler做的是copy initialize。當我們省略”="的時候,我們使用的是direct initialization
常見操作:
在這裡插入圖片描述

The string::size_type Type

從邏輯上,string.size()返回一個unsigned int最直接。然而,size函式返回的是string::size_type型別的數值。接下來做一些解釋:

  • string class和其他諸多library typesi一樣,定義了很多配套型別(companion types)。
  • 配套型別的動機,是避免機器和機器之間的差異。
  • size是unsigned type,注意不要混合sign和unsigned的數字
    Warning: 由於歷史原因,併為了與C相容,string literals和標準庫string不是一個型別。

3.2.3 Dealing with the Characters in a string

在這裡插入圖片描述
(c++11) 使用 range for statement去遍歷字串每個字元

string str("some string");
// print the characters in str one character to a line
for (auto c : str) // for every char in str
 cout << c << endl; // print the current character followed by a newline

相關文章