天天看點

C++進階程式設計總結

C++進階程式設計總結​​C++進階程式設計筆記​​

1. 頭檔案添加注釋(檔案名, 作者, 函數簡介, 日期).

2. 當頭檔案數目較多時, 應将頭檔案放在include目錄下, 源檔案放在source目錄下.

3. const常量有資料類型, 宏常量沒有資料類型.

4. 對于重載指派運算符, 應該用"引用傳遞"方式

5. 函數入口處用assert檢查

6. 記憶體配置設定方式有三種, 從靜态存儲區域配置設定, 從棧上配置設定, 從堆上配置設定, 靜态存儲區包括全局變量,

static變量等.

7. C++/C語言,沒有辦法知道指針所指的記憶體容量.

8. 指針消亡了, 不表示所指的記憶體會被自動釋放。記憶體被釋放了,

不表示指針會消亡或者成了NULL指針.

9. 指針被free或delete之後, 别忘記設定為NULL.

10. malloc不調用構造函數, new自動調用構造函數,

free和delete類似.

11. 為什麼要用重載? (1) 便于記憶。(2) 不得不, 比如說類的多個構造函數

12. 不能編譯頭檔案

全局變量定義時, (直接指派), extern無作用

全局變量聲明時, extern告訴編譯器, 定義部分在其它子產品中

全局變量預設extern

13. 重載: 同一個類中, 或都是全局函數.

覆寫: 分别位于派生類與基類中, 函數名與參數都相同,有virtual關鍵字,用于多态.

隐藏: 分别位于派生類與基類中, 隻要同名, 且非覆寫, 均為隐藏.

14. 函數參數的預設值,隻能出現在函數的聲明中.

15. 操作符重載。調用時, 普通函數參數出現在圓括号内, 對于運算符, 參數出現在其左右兩側。定義時,可定義為全局函數和類的成員函數,後者比前者少了一個參數。

16. 類的構造次序,先構造基類,再構造構造函數的參數,再構造成員,再構造自己。析構完全相反。

17. String a("hello"); String b=a; 其實是調用了b的拷貝構造函數,最好寫成String b(a).

18. 對于一個類,編譯器預設生成4個函數,無參構造函數,拷貝構造函數,析構函數,指派函數

19. 類的析構函數,應為虛函數, 多态

20. 對于非内部資料類型的輸入參數,應該将“值傳遞”的方式,改為“const 引用傳遞”,目的是提高效率。例如,将void Func(A a),改為 void Func(const A &a)。

21. 引用被建立的同時,必須被初始化,一旦引用被初始化,就不能改變引用的關系。

22. 對比于C語言的函數,C++增加了重載,内聯,const和virtual四種新機制,重載和内聯機制,既可以用于全局函數,也可用于類的成員函數,const與virtual機制,僅用于類的成員函數

23. 指派符号的重載,不能為友元,隻能是類的成員函數

C++進階程式設計

C++程式設計學習

概述

C++進階程式設計總結

 面向對象的方法簡介

對象----存在即合理

抽象性–物以類聚

封裝----事物的封閉性

繼承----事物的相似性

多态----事物的多樣性

面向對象方法(類與對象)

C++進階程式設計總結

 C++概述

1.什麼是C++?

C to C++:

* C語言的超集

* 面向對象程式設計

* 可移植性,不犧牲性能和底層功能

C++ compiler:将C++代碼翻譯為C代碼

C++進階程式設計總結

 2.C++适合?

* 算法

* 應用開發

* C/C++伺服器

C++設計原則

C++設計成使用靜态型别機制、與C同樣高效,可移植的,多用途程式設計語言。

C++設計成直接的和廣泛的,支援多種程式設計風格(程式化程式設計、資料抽象化、面向對象程 序設計、泛型程式設計)。

C++設計成給程式設計者,更多的選擇,即使可能導緻程式設計者選擇錯誤。

C++設計成盡可能與C相容,提供一個從C到C++的平滑過渡。

C++避免平台限定,或沒有普遍用途的特性。

C++不使用會帶來額外開銷的特性。

C++設計成無需複雜的程式設計環境。

UNIX鐵律: K.I.S.S-Keep It Simple,Stupid!

C++進階程式設計總結

 &參考

C++大學教程(推薦)

C++Primer

C++程式設計思想

&開發環境

Visual Studio 201X Community

Code::Block

Qt Creator

C++的第一個程式

第一個C++程式:

#include<iostream>

int main(void)

{

   std::cout<<"hello world!"<<std::endl;

    return 0;

}

流的概念及用途

C++的I/O是以位元組流的形式實作的,流(stream)實際上就是一個位元組序列。

輸入流: 在輸入操作中,位元組從輸入裝置(如鍵盤、磁盤、網絡連接配接等)流向記憶體;

輸出流: 在輸出操作中,位元組從記憶體流向輸出裝置(如顯示器、列印機、磁盤、網絡連接配接等);

這裡“流”,試圖說明字元,随着時間順序生成或消耗的。

輸人/輸出系統的任務,實際上就是以一種穩定、可靠的方式,在裝置與記憶體之間傳輸資料。

C++并沒有直接定義,進行輸入輸出的任何語句,這些功能是由标準IO庫完成。

命名空間(namespace)

實際上就是,一個由程式設計者命名的記憶體區域,程式設計者,可以根據需要指定一些有名字的空間域,把一些全局實體,分别放在各個命名空間中,進而與其它全局實體分隔開來。

命名空間是ANSIC++引入的,可以由使用者命名的作用域,用來處理程式中,常見的同名沖突。

std::cout std::cin std::endl

+使用命名空間:

using std::cout;

using namespace std;

using namespace std; //使用命名空間

    cout<<"hello world!"<<endl;

C++程式的執行過程

1.C++主要有三個編譯階段:預處理、轉譯成目标代碼和連結(最後的兩個階段,一般才視為真正的“編譯”)。

2.C++預處理指令和C基本相同

C++進階程式設計總結

 C/C++的字元串比較

0.C語言字元串練習 char st[100];

0.C++語言字元串練習 string str;

1.檢測字元串長度 int len = strlen(st);

1.檢測字元串長度 int len = str.length();

2.字元串比較 strcmp(st1, st2);

2.字元串比較 str1.compare(str2);

3.在已有字元串後,追加新串 strcat(st1, st2); strncat(st1,st2,n);

3.在已有字元串後,追加新串 str1 += str2; str1.append(str2);

4.字元串拷貝 strcpy(st1,st2); strncpy(st1,st2, n);

4.字元串拷貝 str2 = str1; str2 = str1.substr();

5.字元串查找 where = strchr(st, ch)

5.字元串查找 where = str1.find(str2);

#include<string>

    stringstr("hello");

    cout <<str.length() << endl;

    str.append("world!");//在已有字元串後追加新串

    cout << str<< endl;

C/C++資料類型與變量

C++進階程式設計總結

 C/C++變量

程式運作過程中,值能否發生改變,分為**常量和變量**

從變量作用域的大小考慮:全局變量,局部變量

全局變量:定義在所有的函數體之外,在程式開始運作時,配置設定存儲空間,在程式結束時,釋放存儲空間

函數中定義的變量,稱為局部變量(Local Variable)

從變量的生命周期考慮: 靜态生存周期和動态生存周期

動态存儲變量:變量僅在需要的時候,配置設定和占用記憶體

靜态存儲變量:變量在程式運作過程中,占用固定的記憶體

從變量的在記憶體中位置考慮:普通變量與指針變量

C++進階程式設計總結

 動态記憶體配置設定

所謂動态記憶體配置設定,指在程式運作期間,根據實際需要随時申請記憶體,在不需要時釋放

new/delete是C++的運算符

用于申請動态記憶體和釋放記憶體

new運算符的文法格式為:指針=new 資料類型;

• int *p=new int;

• int *p=new int[30];

delete運算符的功能,用來删除是用new建立的對象,或一般類型的指針,其格式如下:delete<指針名>

使用delete,也可以用來删除使用new建立的對象數組,其使用格式如下:delete [] 指針名

#include<string.h>

int main()

    char *str;

    str = new char[10];

   strcpy(str,"hello");

    delete []str;

杜絕“野指針”

指針用來存放某個變量的位址值的一種變量

“野指針”不是NULL指針,指向“垃圾”記憶體的指針,“野指針”的危險之處,在于if語句不起作用。

任何指針變量剛被建立時,不會自動成為NULL指針,預設值是随機的。是以,指針變量在建立的同時,應當被初始化,要不将指針設定為NULL,要麼指向合法的記憶體。

char *p = NULL;

char * str = (char *)malloc(100);

指針p被free或者delete之後,應設定為NULL。

指針操作超越了變量的作用範圍

程式不能傳回指向棧記憶體的指針或引用。

數組與指針

-任何一個數組的名字是一個常量指針,值是該數組的首元素的位址值

-在C++中引用一個數組元素,有兩種等價的方法:

-下标法:如a[j]或p[j]形式,比較直覺

-指針法:如*(a+j)或 *(p+j)形式,比較高效

-數組名作為函數形參時,在函數體内,失去了本身的内涵,僅僅是一個指針。

-指向數組的指針,另外一種變量類型(在linux或win32平台下,長度為4),僅僅意味着數組的存放位址;

數組指針與指針數組

總結

new運算符根據對象的類型,自動決定其大小,不使用sizeof運算符,malloc要指定配置設定存儲空間的大小;

new傳回指向此類型的指針,不用進行強制指針類型轉換。malloc傳回指向void*類型的指針。

如果在申請動态記憶體時,找不到足夠大的記憶體塊,malloc和new将傳回NULL指針,宣告記憶體申請失敗

用free或delete釋放記憶體之後,沒有将指針設定為NULL。導緻産生“野指針”。防止使用指針值為NULL的記憶體。

動态記憶體的申請與釋放必須配對,防止記憶體洩露。

引用與函數傳參

什麼是引用?

引用就是某一變量(目标)的一個别名,對引用的操作與對變量直接操作完全一樣。

引用(&)在此是起标示作用,不是求位址運算,定義格式

<類型>&<引用名>(<變量名>);

<類型>&<引用名>=(<變量名>);

int a = 3;

int &m = a; //定義引用并初始化

int n = m; //将引用賦給變量

int *p = &m;

m = m + 5; // a = 8, 對引用的操作,就是對被引用者的操作

引用詳解

初始化與指派

定義引用時,必須初始化;

可以将一個引用賦予給某個變量;

引用聲明完畢後,相當于目标變量名有兩個名稱,即該目标原名稱和引用名,不能再把該引用名,作為其它變量名的别名。

指針和引用的差別

指針通過位址,間接通路某個變量

引用通過别名,直接通路某個變量

引用一般用作函數的參數,或函數的傳回值

如果既要利用引用提高使用效率,又要保護傳遞給函數的資料,不在函數中被改變,就應當使用常引用。

引用的用途

C語言中沒有引用,C++中才有引用,引用的主要用途,就是在函數傳參和傳回值上。

使用引用作為傳遞函數的參數,在記憶體中,沒有産生實參的副本,直接對實參操作。

如果輸入參數,以值傳遞的方式傳遞對象,宜改用“const &”方式來傳遞,這樣可以省去臨時對象的構造和析構過程,提高效率。

如果既要利用引用,調高使用效率,又要保護傳遞給函數的資料,不在函數中被改變,就應當使用常引用。

如果函數的傳回值是一個對象,有些場合,用“引用傳遞”替換“值傳遞”,可以提高效率,有些場合不可以。

常引用

聲明一個引用,不是新定義一個變量,隻是該引用名是目标變量的一個别名,本身不是一種資料類型,引用不占存儲單元。對引用取位址,就是對目标變量取位址

非const引用,隻能綁定到該引用同類型的變量。const引用,可以綁定到不同,但相關類型的對象, 或着綁定到右值。

常引用的聲明方式:

const 類型标示符 &引用名 = 目标變量名;

用這種方式聲明的引用,不能通過引用,對變量的值進行修改,但目标自身任然能夠改變,這是語言的不一緻性。

    double dvalue = 3.14;

    const int &pd =dvalue;

    dvalue = 50.6;

    cout << pd<<"\n"<<dvalue <<endl;

函數傳回一個類型的引用

注意:不允許傳回的引用,對應于一個局部變量

int &getlnt(const int v)

    int *p = new int(v);

    return *p;

    int &n =getlnt(123456789);

    cout << n<< endl;

    int *pp = &n;

    delete pp;

return語句,不可傳回指向“棧記憶體”的,“指針”,或者“引用”,該記憶體在函數體結束時,被自動銷毀。

C/C++函數說明

C++函數說明

C/C++中的函數說明:

四個組成部分:傳回類型、函數名、形式參數表、函數體

函數的申明與實作,函數的調用與傳參(形參與實參)

函數與指針:指針函數與函數指針

C++增強了函數類型:

基礎函數:内聯函數,函數重載,模闆函數(泛型程式設計)

成員函數:構造/析構函數,常成員函數,靜态成員函數,虛函數

内聯函數(inline)

内聯(内嵌)函數,主要解決的是程式的運作效率問題。

解決手段,在編譯階段,編譯器就會把每次調用内聯函數的地方,都替換為該函數體内的代碼。

引入原因:解決程式中,一些函數體代碼不是很大,卻有被頻繁調用的函數,調用效率問題。

解決方法:以目标代碼的增加為代價,換取時間上的節約。

C++進階程式設計總結

 當在一個函數定義或聲明前,加上關鍵字inline,則把該函數定義為内聯函數。

inline int f(int x)

    return x * x;

    int x(2);

    cout << f(x)<< endl;

    cout << f(x +1) <<endl;

使用内聯函數的注意事項

内聯函數的定義,必須出現在該函數第一次被調用前;

内聯函數不能有複雜的控制語句,如switch,goto和while。

遞歸函數不能是内聯函數。類結構中所有的在類,說明内部定義的函數,都是内聯函數。

内聯函數具有與帶參的宏定義#define,相同的作用和相似的機理,但内聯函數具有宏定義所沒有的優點,沒有缺點,消除了宏定義的不安全性。

函數重載

函數重載又稱為函數的多态性

指同一個函數名對應着多個不同的函數。

“不同”是指,這些函數的形參表,必須互不相同,或者是形參的個數不同,或者是形參是類型不同,或者是兩者都不相同,否則,将無法實作函數重載。

下面是合法的重載函數:

int funcl (int ,int);

int funcl(int );

double funcl(int,long);

double funcl(long);

#include <iostream>/*函數重載*/

int add(int,int);

double add(double,double);

cout<<add(10,20)<<endl;

cout<<add(10.0,20.5)<<endl;

int add(int x,int y)

cout<<"int"<<endl;

return x+y;

double add(double x,double y)

cout<<"double"<<endl;

注意:

重載函數的類型,即函數的傳回類型,可以相同,也可以不同。如果僅僅是傳回類型不同,函數名相同、形參表也相同,則是不合法的,編譯器會報“文法錯誤”。如:

int funcl (int a,int b);

double funcl (int a,int b);

除形參名外都相同的情況,編譯器不認為是重載函數,隻認為是對同一個函數原型的多次聲明。

在調用一個重載函數funcl()時,編譯器必須判斷函數名funcl,到底是指哪個函數。通過編譯器,根據實參的個數和類型,對所有funcl()函數的形參一一進行比較,調用一個最比對的函數。

帶預設參數值的函數

在C++語言中調用函數時,通常要為函數的每個形參,給定對應的實參。若沒有給出實參,按指定的預設值進行工作。

當一個函數既有定義,又有聲明時,形參的預設值,必須在聲明中指定,不能放在定義中指定。隻有當函數沒有聲明時,才可以在函數定義中指定形參的預設值。

預設值的定義,必須遵守從右到左的順序,如果某個形參沒有預設值,則左邊的參數就不能有預設值。如:

void funcl(int a, double b=4.5, int c=3);//合法

void funcl(int a=1, double b, int c=3);//不合法

在進行函數調用時,實參與形參按從左到右的順序進行比對,當實參的數目少于形參時,如果對應位置形參,沒有設定預設值,就會産生編譯錯誤;如果設定了預設值,編譯器将沒有對應實參的形參取預設值。

注意

形參的預設值,可以是全局常量、全局變量、表達式、函數調用,但不能為局部變量。例如,

下例不合法:

void funcl()

int k;

void g(int x=k);//k為局部變量

使用預設參數時,主要滿足函數重載條件;

void fun (int x, int y=0);

void fun(int x);

此時函數fun不能進行重載,因為編譯器不能唯一确定,調用哪個函數(fun(3)或fun(3,0)均可)。

##封裝性

封裝是面向對象的特征之一,對象和類概念的主要特性。

封裝,也就是把客觀事物封裝成抽象的類,類可以把自己的資料和方法,隻讓可信的類,或者對象操作,對不可信的進行資訊隐藏。

具備封裝性(Encapsulation)的面向對象程式設計,隐藏了某一方法的具體執行步驟,取而代之的是通過消息傳遞機制傳送消息。

封裝

關鍵字:public、protected、prviate

• 修飾成員變量和成員函數;

• 繼承時使用

破壞封裝:關鍵字friend

• 友元類和友元函數

封裝好的結構體

#include <iostream>

#include <string.h>

struct Person

    char *m_name;

    int m_age;

    void setName(constchar*);

    void setAge(int);

    void disp();

};

void Person::setName(const char* name)

    m_name = newchar[100];

    strcpy(m_name, name);

void Person::setAge(int age)/*作用域=作用域名+作用域符*/

    m_age = age;

void Person::disp()

    cout <<"Name:" << m_name << endl;

    cout <<"Age:" << m_age << endl;

    Person somebody;

   somebody.setName("DaXian666");

    somebody.setAge(23);

    somebody.disp();

定義類來實作資料隐藏

class Person

private://資料

public://函數

void Person::setName(const char*name)

void Person::setAge(int age)

    cout << "Name:" <<m_name <<endl;

    Person p;

   p.setName("DaXian666");

    p.setAge(23);

    p.disp();

如何實作資料隐藏

引入class類型

對資料成員進行保護

增加存取範圍

• 私有成員private

• 保護成員protected

• 公共成員public

在C++中,class與struct的差別:

struct的預設作用域為public

class的預設作用域為private

類定義格式的構成

說明部分:說明類中的成員,包含資料成員的說明和成員函數的說明;

實作部分:對成員函數的定義

類的一般定義格式

C++進階程式設計總結

類與對象

C++是為了解決編寫大程式過程中的困難而産生的。

對象:客觀世界中任何一個事物,都可以看成一個對象( object )。

對象組成:

資料——描述對象的屬性

函數——行為(操作代碼),根據外界給的資訊進行相應操作的代碼,外界給的資訊進行相應操作的代碼。

具有相同的屬性和行為的對象抽象為類(class )

類是對象的抽象

對象則是類的特例

類中的權限

一般的做法:将需要被外界調用的成員函數指定為public,類的對外接口。

并非要求把所有成員函數都指定為public

有的函數不是準備為外界調用的,支援其它函數的操作,就應該指定為private 。

這種函數稱為其它成員的工具函數(utility function),類外使用者不能調用。

私有的成員函數隻能被本類中的其它成員函數所調用,不能被類外調用。

成員函數可以通路本類中任何成員(包括私有的和公用的),可以引用在本作用域中有效的資料。

C++ 标準庫

#pragma once

//上下等價

#ifndef BitFlip_H

#define BitFlip_H

//the content of BitFlip_H header file

#endif // !BitFlip

1. 切勿在頭檔案中,使用using指令,或者using 聲明,否則,添加頭檔案,都要用這個空間。

2. 命名空間嵌套在17标準中,得到了極大的簡化

3. 聲明變量的時候不指定值,變量的值取決于這塊記憶體的值

4. 允許if中加入初始化器

if (int a = 0;a>0) {

    }

5.

std::array<int, 3> arr = { 1,1,1 };//固定大小#include<array> 11标準

    intsize=std::size(arr);

6. C++程式中記憶體分為堆和棧,函數的執行一般在棧上進行,用完釋放。明确的配置設定記憶體,一般是放在了堆上。(在函數中聲明的,也要釋放掉)

int* a;

    *a = 0;

    delete a;//delete[]a---删除數組

    a = nullptr; 删除指針後,最好進行置空操作,防止再次的使用

7.

//make_unique在超過作用域,或者被删除時,就會自動釋放記憶體資源

    autoan=make_unique<BitFlip>();

    //共享指針,每次指定make_shared時,都會遞增一個引用計數,表示資料又多了一個擁有者,當超過作用域時,就遞減引用計數,直到為0時,釋放資源

    auto an1 =make_shared<BitFlip>();

8.const多種用法(如果需要給函數傳遞對象,最好按const引用傳遞,這樣可以防止多餘的複制。如果需要改變對象,則需要傳遞非const引用)

//保護參數

void get(const string* a) {

    *a ="ddd";//不通過

const int a = 1;  //保證代碼不會改變該變量的值

//變量x和引用變量re,指向同一個值,改變一個,都會變

    int x = 1;

    int& re = x;

9.auto 去除了const限定和引用 因為auto建立一個副本。除非用auto &

//第一,const函數傳回值(即指針)的内容不能被修改,該傳回值隻能被賦給加const修飾的同類型指針

//第二,任何不會修改資料成員的函數,都應該聲明為const類型。如果在編寫const成員函數時,不慎修改了資料成員,或者調用了其它非const成員函數,編譯器将指出錯誤,無疑會提高程式的健壯性

const int& Get() const {

繼續閱讀