2020年7月11日 星期六

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (3) - Type Aliases



Type Aliases

    創造資料型態的同義詞,通常是用 typedef 來去實現。
    typedef double wages;   // wages is a synonym for double
    typedef wages base, *p; // base is a synonym for double, p for double*

auto

    寫程式常會有想要一個 variable 去儲存 expression 的運算結果,但要事先知道 expression 的最終資料型態非常困難。所以有 auto 這個特別的資料型態,讓編譯器決定其資料型態,但相對的 variable 一定要 initialize。
    auto item = val1 + val2; // item initialized to the result of val1 + val2
    因為 auto 一次只能當一個資料型態,所以在宣告時如果是用 ", " 分開的複數宣告,資料型態要一致。
    auto i = 0, *p = &i;      // ok: i is int and p is a pointer to int
    auto sz = 0, pi = 3.14;   // error: inconsistent types for sz and pi
    auto 與 const 的互動,基本上 auto 會忽視 top level const ( 物件本身為 const )。
    const int ci = i, &cr = ci;
    auto b = ci;       // b is an int (top-level const in ci is dropped)
    auto c = cr;       // c is an int (cr is an alias for ci whose const is top-level)
    auto d = &i;       // d is an int*(& of an int object is int*)
    auto e = &ci;      // e is const int*(& of a const object is low-level const)
    若想要個 top level auto const,你只能在 auto 前加 const 修飾詞。
    const auto f = ci; // deduced type of ci is int; f has type const int

decltype()

    不同於 auto,decltype() 可以不用去計算 expression,只讓編譯器去分析其資料型態。下面程式碼,編譯器不會呼叫 f(),而是去檢查 f() 的 return 資料型態去給予 sum。
    decltype(f()) sum = x;     // sum has whatever type f returns
    decltype() 也可以與 top level const 互動。
    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
上一篇 :

2020年7月9日 星期四

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (2) - Const



修飾詞 : Const

    如果我們想要一個不可被改變的參數,這時就會需要這個修飾詞 ( Qualifier ) const。
    const int bufSize = 512;  // input buffer size
    bufSize = 1024;           // error: attempt to write to const object

Const + Reference

    Const + Reference 代表 Reference to const,等於你不能使用這個 Reference 去改變物件。沒有 const 修飾詞 ( plain object ) 的 reference 不可以 bind 有 const 修飾詞的物件,但反之有 const 修飾詞的 reference 可以 bind 無 const 修飾詞的物件。
    int i = 1;
    const int &r = i;  // we can bind a const int& to a plain int object
    i = i + 1;         // "r" will be 2 too.
    r = r + 1;         // error: assignment of read-only reference "r"
    int &j = r;        // error: binding ‘const int’ to reference of type ‘int&’ discards qualifiers

Const + Pointer ( const type * var )

    跟 Reference 一樣 Pointer to const,等於你不能使用這個 Pointer 去改變物件。沒有 const 修飾詞 ( plain object ) 的 Pointer 不可以 bind 有 const 修飾詞的物件,但反之有 const 修飾詞的 Pointer 可以 bind 無 const 修飾詞的物件。
    const double pi = 3.14;     // pi is const; its value may not be changed
    double *ptr = π          // error: ptr is a plain pointer
    const double *cptr = π   // ok: cptr may point to a double that is const
    *cptr = 42;                 // error: cannot assign to *cptr

Const + Pointer ( type * const var )

    但 Pointer 跟 Reference 不一樣,本身也是物件,所以可以 const pointer。const pointer 則必須被 initialized。但因為是 const pointer 而不是 const 指向物件,所以可以用 const pointer 去改變物件。
    int numb = 0;
    int * const cptr1 = &numb;  // cptr1 will always point to numb
    int * const cptr2;          // error: uninitialized const 'cptr2'
    *cptr1 = 5;                 // numb will be 5 too.

top-level/lower-level const

    像 pointer 的 const 就有兩種,所以稱 const pointer object 這種本身為 top-level,稱 point to const 這種為 lower-level。
    int i = 0;
    int *const p1 = &i;       // we can't change the value of p1; const is top-level
    const int ci = 42;        // we cannot change ci; const is top-level
    const int *p2 = &ci;      // we can change p2; const is low-level
    const int *const p3 = p2; // right-most const is top-level, left-most is not
    const int &r = ci;        // const in reference types is always low-level

constexpr ( constant expression )

    constant expression 等於 expression 不能被改變,也就等於這個 expression 必須在編譯時期就可以被計算出來。以下為 constant expression 的例子。
    const int max_files = 20;        // max_files is a constant expression
    const int limit = max_files + 1; // limit is a constant expression
    int staff_size = 27;             // staff_size is not a constant expression
    const int sz = get_size();       // sz is not a constant expression
    int i; 
    const int size1 = i; 
    constexpr int size2 = i;      // error: the value of ‘i’ is not usable in a constant expression
    constexpr int mf = 20;        // 20 is a constant expression
    constexpr int limit = mf + 1; // mf + 1 is a constant expression
    constexpr int sz = size();    // ok only if size is a constexpr function
    constexpr 跟 pointer 的作用
    const int *p = nullptr;       // p is a pointer to a const int
    constexpr int *q = nullptr;   // q is a const pointer to int
相關文章 :
上一篇 :
下一篇 :

2020年7月3日 星期五

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (1) - Primitive Types



C++ 原生內建的資料型態 ( Primitive Types )

    C++ 定義了一些算術用的資料型態 ( Arithmetic Types ) 和一個特殊的資料型態 void。Arithmetic Types : Integer, Character, Boolean, Floating Point, Double Floating Point, Wide Character。

    下面為一些資料型態轉換 :
    bool b = 42;            // b is true
    int i = b;              // i has value 1
    i = 3.14;               // i has value 3
    double pi = i;          // pi has value 3.0
    unsigned char c = -1;   // assuming 8-bit chars, c has value 255
    signed char c2 = 256;   // assuming 8-bit chars, the value of c2 is undefined

Initialization

    各種初始 :
    int units_sold1 = 0;
    int units_sold2 = {0};
    int units_sold3{0};
    int units_sold4(0);
    {} 跟 () 的不同 :
    long double ld = 3.1415926536;
    int a{ld}, b = {ld};    // error: narrowing conversion required
    int c(ld), d = ld;      // ok: but value will be truncated

Declaration 跟 Definition

    為了支援多個檔案的編譯,cpp 區分了 Declaration 跟 Definition。Declaration 代表著跟整個程式宣告一個帶有資料型態的名子,任何檔案都可以去作存取。Definition 則是創造一個物件實體去對應那個帶有資料型態的名子。
    如果想要只宣告名子(代表實際物件會被在其他檔案給實現),則會在宣告時加上 extern,有了 extern 就代表你不能下 Definition。
    extern int i;              // declares but does not define i
    int j;                     // declares and defines j
    extern double pi = 3.1416; // error: ‘pi’ has both ‘extern’ and initializer

Compound Types - References

    Reference 等於創造額外的一個名子給一個物件。所以下面第 refVal2, refVal4 會 error,因為你不能給不存在的物件 ( 或 rvalue ) 取名。References must be initialized.
    int ival = 1024;
    int &refVal = ival;     // refVal refers to (is another name for) ival
    int &refVal2;           // error: a reference must be initialized
    int &refVal3 = refVal;  // ok: refVal3 is bound to the object to which refVal is bound, i.e., to ival
    int &refVal4 = 10;      // error: initializer must be an object

Compound Types - Pointers

    Pointer為一個 "指向" 物件。類似 References 但卻是一個物件,所以可以不用被 initialized,也可以用來複製、分配。下面的 & 是作為 operator,用來取物件的實際位置,與上面提到用來宣告資料型態的的 & 有著不同的意義。
    double dval;
    double *pd = &dval; // ok: initializer is the address of a double
    double *pd2 = pd;   // ok: initializer is a pointer to double
    int *pi = pd;       // error: types of pi and pd differ
    pi = &dval;         // error: assigning the address of a double to a pointer to int
    下面的 * 作為 operator,放在 pointer 前面等於取其指向的該物件
    *p = 0;             // * yields the object; we assign a new value to ival through p
    std::cout << *p;    // prints 0

更多 References & Pointers 範例

    double dval;
    double *pd = &dval;  // ok: initializer is the address of a double
    double *pd2 = pd;    // ok: initializer is a pointer to double
    int *pi = pd;        // error: types of pi and pd differ
    pi = &dval;          // error: assigning the address of a double to a pointer to int

    int i = 42;
    int &r = i;          // & follows a type and is part of a declaration; r is a reference
    int *p;              // * follows a type and is part of a declaration; p is a pointer
    p = &i;              // & is used in an expression as the address-of operator
    *p = i;              // * is used in an expression as the dereference operator
    int &r2 = *p;        // & is part of the declaration; * is the dereference operator
相關文章 :
上一篇 :
下一篇 :

2020年6月14日 星期日

讀書心得 - C++ Primer (5th Edition) - Chapter 1

簡單的 C++ 程式

    要寫一個 C++ 程式跟 C 一樣,寫好 cpp 檔,交給編譯器 ( g++ ) 編成可執行程式。程式至少包含一個名為 main 的 function,用以當作程式的入口 function。
    int main() {
        return 0; // return 0 的原因為 0 通常代表著程式執行成功。
    }

Input/Output

    C++ 本身並沒有定義 I/O,需要額外的標準函式庫,iostream。
    #include <iostream>
    int main()
    {
        // operator << >> 會回傳左邊的 operand
        // 以 std::cin >> v1 >> v2; 為例
        // 執行結果 =
        //     std::cin >> v1;
        //     std::cin >> v2;
        int v1, v2;
        std::cout << "Enter two numbers:" << std::endl;
        std::cin >> v1 >> v2;
        std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl;
        return 0;
    }

Note

常用詞彙

  • prompt 提示 驅使

    We can extend our main program to prompt the user to give us two numbers and then print their sum

  • expression (數學中的)式,表達式

    The smallest unit of computation. An expression consists of one or more operands and usually one or more operators. Expressions are evaluated to produce a result. For example, assuming i and j are ints, then i + j is an expression and yields the sum of the two int values.

  • angle brackets : <>

  • quotation marks : ""

  • curly braces : {}

  • operator : 運算子

  • operand : 運算元

  • assignment

    Obliterates an object’s current value and replaces that value by a new one.

  • comments : 註解

  • statement : wiki

    The new part of this program is the while statement.A while has the form

    while (condition)
        statement

    A while executes by(alternately) testing the condition and executing the associated
    statement until the condition is false.A condition is an expression that yields a result
    that is either true or false..So long as condition is true, statement is executed.
下一篇 :

2020年5月24日 星期日

Cpp - &

C++ 的 &


    C++ 的 & 比起 C 語言的提取位置,還多了宣告引用 必須在定義時候就進行初始化 )。
    int a = 5;
    int &b = a;
    std::cout << "a value\t\t" << a << "\n";
    std::cout << "a address\t" << &a << "\n";
    std::cout << "b value\t\t" << b << "\n";
    std::cout << "b address\t" << &b << "\n";
    int c = 50;
    b = c;
    std::cout << "a value\t\t" << a << "\n";
    std::cout << "a address\t" << &a << "\n";
    std::cout << "b value\t\t" << b << "\n";
    std::cout << "b address\t" << &b << "\n";
    std::cout << "c value\t\t" << c << "\n";
    std::cout << "c address\t" << &c << "\n";
a value         5
a address       0x61ff08
b value         5
b address       0x61ff08
a value         50
a address       0x61ff08
b value         50
b address       0x61ff08
c value         50
c address       0x61ff04


參考資料 :

C/C++ - 左值、右值 ( lvalue、rvalue )

lvalue、rvalue 基本概念

左值 (lvalue) : 一個佔據某個特定記憶體的值。
右值 (rvalue) : 一個 expression 結束後就消失的值。
基本上這兩個定義包含了全部的值,非左即右,非右即左。
    int var = 4;    // var 參數佔據記憶體 = lvalue
    4 = var;        // 4 不佔據記憶體 = rvalue
    (var + 1) = 4;  // var + 1 也不佔據記憶體 = rvalue
    以上 2 跟 3 行會報錯,lvalue required as left operand of assignment。表示這個賦值程式碼錯在給不存在的記憶體空間賦值。所以只要是 lvalue 就能賦予值,即使是 function 也一樣,下面的 function 引用一個左值 ( globalvar ),所以可以賦予值。
    int globalvar = 20;

    int &foo() {
        return globalvar;
    }

    int main() {
        foo() = 10;
        std::cout << globalvar; // 10
        return 0;
    }

lvalue、rvalue 轉換


    左值能直接的轉換成右值,但右值卻不行,這時就會需要 ' * ' 。
    int a = 1;
    int b = a + 1;  // 這裡的 a 被直接視為右值
    int arr[] = {a, b};
    int *p = arr;
    *(p + 1) = 10;  // 利用 * 將右值 (p + 1) 傳換成左值


參考資料 :

Popular Posts