1. 程式人生 > >《C++程式設計思想》讀書筆記

《C++程式設計思想》讀書筆記

0.前言

說是對本科期間來個總結,不如乘著暑假不忙看兩本書,先看著本,主要記錄不熟的和不瞭解的地方。
這裡寫圖片描述

1.正文

第1卷 標準C++導引

第一章 物件導論[0-37](2018.7.2)

這一章主要介紹面向物件思想和專案管理經驗(暫時沒有感性認識)

第二章 物件的建立與使用[38-56](2018.7.3)

1.extern 關鍵字
一般宣告一個變數的同時就為他分配了空間,即定義該變數,若只是宣告一個變數但不定義它,則使用extern關鍵字

//他表示變數是定義在檔案以外的,**或者在本檔案的後面部分才定義**
extern int a;

2.字元陣列的拼接
c前處理器的一個重要的功能就是可以進行字元陣列的拼接,即兩個加引號的字元陣列鄰接,並且他們之間沒有標點,編譯器就會把這些字元陣列連線成單個字元陣列。

    char s[100]="sdhuisabdiusa"
                "sdnsoiadnisoa"
                "sdianosidnoiasd";

3.c語言system()函式
其主要用於發出一個DOS命令,簡單使用實現一個閃閃發光的螢幕。

#include<iostream>
#include<cstdlib>
#include"random.h"
using namespace std;
int main()
{
    int f=0,l=0;
    char s[20];
    while(1)
    {
        f=getRandomInt(0
,9); l=getRandomInt('A','F'); sprintf_s(s,"color %d%c",f,l); system(s); } return 0; }

第三章 對標準C++導引[57-118](2018.7.4-17)

1.靜態變數
(1)static定義函式區域性變數時,變數在函式呼叫第一次時執行,函式呼叫之間變數的值保持不變,優點在於函式範圍之外他是不可用的。
(2)static位於函式名或所有函式外部的變數時,他的意思是“在檔案的外部不可以使用這個名字”,即為檔案作用域。
2.連線
函式之外定義的所有變數(C++中除了const)和函式定義預設為外部連線,也可以用static強制為內部連線,也可以在定義時使用extern顯式指定外部連線。
在c中不必用extern定義變數或函式,但在c++中對於const有時必須使用。
3.C++的顯式轉換

暫時不深究,留在後面

  • static_cast
  • const_cast
  • reinterpret_cast
  • dynamic_cast

    4.sizeof
    sizeof是一個運算子,而非函式,對於一個型別可以使用括號,而對於一個變數,可以去掉括號。

sizeof(int)
sizeof a;

5.結構體的使用
在c語言中使用struct定義結構體後,使用時仍然要加上struct關鍵字,很麻煩,當然也可以加上typedef關鍵字來簡化,在C++中該部分以及可以丟掉這些,定義結構體後直接使用結構體名。

struct MyStruct
{
    int data;
    MyStruct *next;
};

MyStruct t;

6.字元陣列轉數值
以前一直使用C++的辦法(sstream),將字串包裝成字元流,輸出到變數中。C中也提供了相應方法。

    char s1[]="123";
    char s2[]="12345678";
    char s3[]="123.12";

    std::cout<<atoi(s1)<<std::endl;
    std::cout<<atol(s2)<<std::endl;
    std::cout<<atof(s3)<<std::endl;

7.把變數和表示式轉換為字串
標準C具有字串化運算子“#”,在一個前處理器巨集的引數前面加一個#,前處理器會把這個引數轉化為一個字元陣列,便於除錯輸出。

    #define LOG(x) std::cout<<#x <<" = "<<x<<std::endl;
    int a=1,b=2;
    LOG(1);
    LOG(a);
    LOG(a+b);
    /*
    1 = 1
    a = 1
    a+b = 3
    */

8.關於除錯可以使用”cassert”的assert函式。給他一個引數,如果引數斷言為假,則發出錯誤資訊,程式終止。完成除錯後,可以在#include<”cassert”>值錢插入語句 #define NDEBUG或者在編譯器命令中定義ndebug,用以消除巨集產生的程式碼。”cassert”中使用ndebug用來改變巨集產生程式碼的方式。

    //#define NDEBUG  
    #include<cassert>
    int a=1,b=2;
    assert(a==b);
    /*
    Assertion failed: a==b 並彈出錯誤框
    vs2012中彈出錯誤框一般很難定位原因
    每當這個時候就開始懷念使用java 
    */

第四章 資料抽象[119-141](2018.7.4-17)

1.有害的函式宣告猜想(C語言)
雖然總是應當通過包含標頭檔案宣告函式,但是在C語言中不是基本的。呼叫沒有宣告的函式在C中是可以的(C++不行),按照C語言的標準,不強迫這樣做,這樣編譯器會假設。例如,在標頭檔案中宣告void f( float )函式,編譯器就知道如果用一個整型引數傳入,則會自動轉換為float,稱為提升。然而若未曾宣告,則編譯器假設有一個f(int)存在,就不做提升了。若此時將int型別資料格式當做float解讀,則可能會產生問題。
2.void* 指標
在C中可以將void* 型別賦值給任何指標,而在C++中是不允許的(因為當將void*指標賦給struct時如果不被阻止,就可能會導致對於struct呼叫邏輯上並不存在的函式)。而C,C++都可以將任何型別的指標賦值給void*,這是void*的最初意圖。
3.封裝
將資料連同函式捆綁在一起 ,這常常被稱為封裝。
4.sizeof確定struct/class的長度(暫時不深究,留在後面
一個結構體的大小理論上是他的所有成員大小的和。當然有時候當一個結構體被編譯器處理時會增加額外位元組來使邊界整齊。這裡提出一種結構體或者類中無資料成員的情況。

//這樣一個無資料成員的類或者說結構體
//其目的在於限定函式名的範圍
class Node2
{
    //char a;
    void  f1();
    void  f2();
    void  f3();
};
void Node2::f1()
{
    int a=0;
}
void Node2::f2()
{
    int a=0;
}
void Node2::f3()
{
    int a=0;
}
int main()
{
    std::cout<<sizeof(Node2);
    return 0;
}

//vs2012輸出 1
//去掉char a前面的註釋,仍然是1
//表明在無資料成員時,編譯器總是規定了最小非0長度

關於類的大小問題可參照c++類大小問題
5.結構巢狀
可以將一個結構體或者類巢狀到另外一個結構體或者類中(struct與class在C++中已經區別不大了)

class Stack
{
public:
    class Node
    {
    public:
        void *data;
        Node *next;
        void initialize(void *dat,Node *nex);
    } * head;
    void  initialize();
    void push(void *dat);
};

void Stack::Node::initialize(void *dat,Node *nex)//這裡比較有意思。
{
    data=dat;
    next=nex;
}
void Stack::initialize()
{ head=0 ;}

void Stack::push(void *dat)
{
    Node * node = new Node;
    node->initialize(dat,head);
    head=node;
}

6.全域性作用域解析
編譯器預設選擇最接近的名字。作用域解析運算子可以避開這個問題。

int a=5;
void f()
{
    std::cout<<"全域性f()"<<std::endl;
}

class s
{
public:
    int a;
    void f();
};

void s::f()
{
    a=100;//區域性a
    ::f();//全域性f()
    std::cout<<::a<<std::endl;//全域性a
}
int main()
{
    s s1;
    s1.f();
    return 0;
}
/*
輸出
全域性f()
5
*/