C++ 基礎

weixin_34146805發表於2017-01-02

C++基礎

1、C++對C的擴充套件

1.1程式設計方法的發展歷程

程式導向的機構化程式設計方法

  • 設計思路

    – 自頂向下、逐步求精。採用模組分解與功能抽象,自頂向下、分而治之。

  • 程式結構

    – 按功能劃分為若干個基本模組,形成一個樹狀結構。

    – 各模組間的關係儘可能簡單,功能上相對獨立;每一模組內部均是由順序、選擇和迴圈三種基本結構組成。

    – 其模組化實現的具體方法是使用子程式。

  • 優點:

    有效地將一個較複雜的程式系統設計任務分解成許多易於控制和處理的子任務,便於開發和維護。

  • 缺點:可重用性差、資料安全性差、難以開發大型軟體和圖形介面的應用軟體

    – 把資料和處理資料的過程分離為相互獨立的實體。

    – 當資料結構改變時,所有相關的處理過程都要進行相應的修改。

    – 每一種相對於老問題的新方法都要帶來額外的開銷。

    – 圖形使用者介面的應用程式,很難用過程來描述和實現,開發和維護也都很困難。

物件導向的方法

  • 將資料及對資料的操作方法封裝在一起,作為一個相互依存、不可分離的整體——物件。
  • 對同型別物件抽象出其共性,形成類。
    • 類通過一個簡單的外部介面,與外界發生關係。
    • 物件與物件之間通過訊息進行通訊。

物件導向的基本概念

物件

  • 一般意義上的物件:

– 是現實世界中一個實際存在的事物。

– 可以是有形的(比如一輛汽車),也可以是無形的(比如一項計劃)。

– 是構成世界的一個獨立單位,具有

​ – 靜態特徵:可以用某種資料來描述

​ – 動態特徵:物件所表現的行為或具有的功能

  • 物件導向方法中的物件:

– 是系統中用來描述客觀事物的一個實體,它是用來構成系統的一個基本單位。物件由一組屬性和一組行為構成。

– 屬性:用來描述物件靜態特徵的資料項。

– 行為:用來描述物件動態特徵的操作序列。

  • 分類——人類通常的思維方法

  • 分類所依據的原則——抽象

    – 忽略事物的非本質特徵,只注意那些與當前目標有關的本質特徵,從而找出事物的共性,把具有共同性質的事物劃分為一類,得出一個抽象的概念。

    – 例如,石頭、樹木、汽車、房屋等都是人們在長期的生產和生活實踐中抽象出的概念。

    • 物件導向方法中的"類"

    – 具有相同屬性和服務的一組物件的集合

    – 為屬於該類的全部物件提供了抽象的描述,包括屬性和行為兩個主要部分。


    類與物件的關係:
    猶如模具與鑄件之間的關係,一個屬於某類的物件稱為該類的一個例項。

封裝

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

  • 把物件的屬性和服務結合成一個獨立的系統單元。

  • 儘可能隱蔽物件的內部細節。對外形成一個邊界(或者說一道屏障),只保留有限的對外介面使之與外部發生聯絡。

    • 繼承對於軟體複用有著重要意義,是物件導向技術能夠提高軟體開發效率的重要原因之一。

    • 定義:特殊類的物件擁有其一般類的全部屬性與服務,稱作特殊類對一般類的繼承。

    • 例如:將輪船作為一個一般類,客輪便是一個特殊類。

    多型

    多型是指在一般類中定義的屬性或行為,被特殊類繼承之後,可以具有不同的資料型別或表現出不同的行為。這使得同一個屬性或行為在一般類及其各個特殊類中具有不同的語義。

物件導向的軟體工程

  • 物件導向的軟體工程是物件導向方法在軟體工程領域的全面應用。它包括:

– 物件導向的分析(OOA)

– 物件導向的設計(OOD)

– 物件導向的程式設計(OOP)

– 物件導向的測試(OOT)

– 物件導向的軟體維護(OOSM)

總結:

程式導向程式設計:資料結構 + 演算法

主要解決科學計算問題,使用者需求簡單而固定

特點:

分析解決問題所需要的步驟

利用函式實現各個步驟

依次呼叫函式解決問題

問題:

軟體可重用性差

軟體可維護性差

構建的軟體無法滿足使用者需求

物件導向程式設計:由現實世界建立軟體模型

將現實世界中的事物直接對映到程式中,可直接滿足使用者需求

特點:

直接分析使用者需求中涉及的各個實體

在程式碼中描述現實世界中的實體

在程式碼中關聯各個實體協同工作解決問題

優勢:

構建的軟體能夠適應使用者需求的不斷變化

直接利用程式導向方法的優勢而避開其劣勢

1.2 C語音和C++語音的關係

  1. C語言是在實踐的過程中逐步完善起來的

​ 沒有深思熟慮的設計過程

​ 使用時存在很多“灰色地帶”

​ 殘留量過多低階語言的特徵

​ 直接利用指標進行記憶體操作

  1. C語言的目標是高效

    最終程式執行效率的高效

  2. 當程式導向方法論暴露越來越多的缺陷的時候,業界開始考慮在工程專案中引入物件導向的設計方法,而第一個需要解決的問題就是:高效的面嚮物件語言,並且能夠相容已經存在的程式碼。

    C語言 + 物件導向方法論===》Objective C /C++

  3. C語言和C++並不是對立的競爭關係

    C++是C語言的加強,是一種更好的C語言

    C++是以C語言為基礎的,並且完全相容C語言的特性

  4. 學習C++並不會影響原有的C語言知識,相反會根據加深對C的認知;

    學習C++可以接觸到更多的軟體設計方法,並帶來更多的機會。

    1) C++是一種更強大的C,通過學習C++能夠掌握更多的軟體設計方法

    2) C++是Java/C#/D等現代開發語言的基礎,學習C++後能夠快速掌握這些語言

    3)C++是各大知名軟體企業挑選人才的標準之一

1337433-1bd925bf87c502df.jpg
圖1-1.jpg

1.3 C++對C的加強

1.3.1 namespace名稱空間

  1. C++名稱空間基本常識

所謂namespace,是指識別符號的各種可見範圍。C++標準程式庫中的所有識別符號都被定義於一個名為std的namespace中。

一 :<iostream>和<iostream.h>格式不一樣,前者沒有字尾,實際上,在你的編譯器include資料夾裡面可以看到,二者是兩個檔案,開啟檔案就會發現,裡面的程式碼是不一樣的。字尾為.h的標頭檔案c++標準已經明確提出不支援了,早些的實現將標準庫功能定義在全域性空間裡,宣告在帶.h字尾的標頭檔案裡,c++標準為了和C區別開,也為了正確使用名稱空間,規定標頭檔案不使用字尾.h。因此,

1)當使用<iostream.h>時,相當於在c中呼叫庫函式,使用的是全域性名稱空間,也就是早期的c++實現;

2)當使用<iostream>的時候,該標頭檔案沒有定義全域性名稱空間,必須使用namespace std;這樣才能正確使用cout。

二: 由於namespace的概念,使用C++標準程式庫的任何識別符號時,可以有三種選擇:

1、直接指定識別符號。例如std::ostream而不是ostream。完整語句如下:std::cout << std::hex << 3.4 << std::endl;

2、使用using關鍵字。 usingstd::cout; using std::endl; using std::cin; 以上程式可以寫成 cout<< std::hex << 3.4 << endl;

3、最方便的就是使用usingnamespace std; 例如: using namespace std;這樣名稱空間std內定義的所有識別符號都有效(曝光)。就好像它們被宣告為全域性變數一樣。那麼以上語句可以如下寫: cout <<hex << 3.4 << endl;因為標準庫非常的龐大,所以程式設計師在選擇的類的名稱或函式名 時就很有可能和標準庫中的某個名字相同。所以為了避免這種情況所造成的名字衝突,就把標準庫中的一切都被放在名字空間std中。但這又會帶來了一個新問題。無數原有的C++程式碼都依賴於使用了多年的偽標準庫中的功能,他們都是在全域性空間下的。所以就有了<iostream.h> 和<iostream>等等這樣的標頭檔案,一個是為了相容以前的C++程式碼,一個是為了支援新的標準。名稱空間std封裝的是標準程式庫的名稱,標準程式庫為了和以前的標頭檔案區別,一般不加".h"

2.C++名稱空間定義及使用語法

/* 在C++中,名稱(name)可以是符號常量、變數、巨集、函式、結構、列舉、類和物件等等。為了避免,在大規模程式的設計中,以及在程式設計師使用各種各樣的C++庫時,這些識別符號的命名發生衝突, 標準C++引入了關鍵字namespace(名稱空間/名字空間/名稱空間/名域),可以更好地控制識別符號的作用域。 */
/* std是c++標準名稱空間,c++標準程式庫中的所有識別符號都被定義在std中,比如標準庫中的類iostream、vector 等都定義在該名稱空間中,使用時要加上using宣告(using namespace std) 或using指示(如std::string、 std::vector<int>). */
/* C中的名稱空間 在C語言中只有一個全域性作用域 C語言中所有的全域性識別符號共享同一個作用域 識別符號之間可能發生衝突 C++中提出了名稱空間的概念 名稱空間將全域性作用域分成不同的部分 不同名稱空間中的識別符號可以同名而不會發生衝突 名稱空間可以相互巢狀 全域性作用域也叫預設名稱空間 */
/* C++名稱空間的定義: namespace name { … } */
/* C++名稱空間的使用: 使用整個名稱空間:using namespace name; 使用名稱空間中的變數:using name::variable; 使用預設名稱空間中的變數:::variable 預設情況下可以直接使用默 認名稱空間中的所有識別符號 */
  1. C++名稱空間程式設計實踐
namespace NameSpaceA
{   
    int a = 0;
}
    
namespace NameSpaceB
{   
    int a = 1;

    namespace NameSpaceC
    {
        struct Teacher
        {
            char name[10];
            int age;
        };
    }
}

int main()
{
    using namespace NameSpaceA;
    using NameSpaceB::NameSpaceC::Teacher;

    printf("a = %d\n", a);
    printf("a = %d\n", NameSpaceB::a);

NameSpaceB::NameSpaceC::Teacher t2
    Teacher t1 = {"aaa", 3};

    printf("t1.name = %s\n", t1.name);
    printf("t1.age = %d\n", t1.age);

    system("pause");
    return 0;
}

4 .結論

1) 當使用<iostream>的時候,該標頭檔案沒有定義全域性名稱空間,必須使用namespace std;這樣才能正確使用cout。若不引入using namespace std ,需要這樣做。std::cout。

2) c++標準為了和C區別開,也為了正確使用名稱空間,規定標頭檔案不使用字尾.h。

3) C++名稱空間的定義: namespacename { … }

4) using namespace NameSpaceA;

5) namespce定義可巢狀。

1.3.2“實用性”增加

#include "iostream"
using namespace std;

//C語言中的變數都必須在作用域開始的位置定義!!
//C++中更強調語言的“實用性”,所有的變數都可以在需要使用時再定義。

int main11()
{
    int i = 0;

    printf("ddd");
    int k;
    system("pause");
    return 0;
}

1.3.3register關鍵字增強

//register關鍵字 請求編譯器讓變數a直接放在暫存器裡面,速度快
//在c語言中 register修飾的變數 不能取地址,但是在c++裡面做了內容

/*
//1
register關鍵字的變化
register關鍵字請求“編譯器”將區域性變數儲存於暫存器中
C語言中無法取得register變數地址
在C++中依然支援register關鍵字
C++編譯器有自己的優化方式,不使用register也可能做優化
C++中可以取得register變數的地址
//2
C++編譯器發現程式中需要取register變數的地址時,register對變數的宣告變得無效。

//3
早期C語言編譯器不會對程式碼進行優化,因此register變數是一個很好的補充。
*/

int main22()
{
    register int a = 0; 

    printf("&a = %x\n", &a);

    system("pause");
    return 0;
}

1.3.4變數檢測增強

/*
在C語言中,重複定義多個同名的全域性變數是合法的
    在C++中,不允許定義多個同名的全域性變數
C語言中多個同名的全域性變數最終會被連結到全域性資料區的同一個地址空間上
int g_var;
int g_var = 1;

C++直接拒絕這種二義性的做法。
*/

1.3.5struct型別加強

struct型別的加強:

C語言的struct定義了一組變數的集合,C編譯器並不認為這是一種新的型別

C++中的struct是一個新型別的定義宣告

struct Student
{
    char name[100];
    int age;
};

int main(int argc, char *argv[])
{
    Student s1 = {"wang", 1};
    Student s2 = {"wang2", 2};    
    return 0;
}

1.3.6C++中所有的變數和函式都必須有型別

/*
C++中所有的變數和函式都必須有型別
    C語言中的預設型別在C++中是不合法的


函式f的返回值是什麼型別,引數又是什麼型別?
函式g可以接受多少個引數?
*/

//更換成.cpp試試

f(i)
{
    printf("i = %d\n", i);

}

g()
{
    return 5;
}

int main(int argc, char *argv[])
{

    f(10);

    printf("g() = %d\n", g(1, 2, 3, 4, 5));


    getchar();  
    return 0;
}

總結:

/*

在C語言中

           intf(    );表示返回值為int,接受任意引數的函式

           intf(void);表示返回值為int的無參函式

           在C++中

           intf(  );和int f(void)具有相同的意義,都表示返回值為int的無參函式

*/                              

C++更加強調型別,任意的程式元素都必須顯示指明型別

1.3.2-1.3.6屬於語法級別的增強。

1.3.7新增Bool型別關鍵字

/*
C++中的布林型別
    C++在C語言的基本型別系統之上增加了bool
    C++中的bool可取的值只有true和false
    理論上bool只佔用一個位元組,
    如果多個bool變數定義在一起,可能會各佔一個bit,這取決於編譯器的實現

    true代表真值,編譯器內部用1來表示
    false代表非真值,編譯器內部用0來表示

    bool型別只有true(非0)和false(0)兩個值
    C++編譯器會在賦值時將非0值轉換為true,0值轉換為false
*/
int main(int argc, char *argv[])
{
    int a;
    bool b = true;
    printf("b = %d, sizeof(b) = %d\n", b, sizeof(b));

    b = 4;
    a = b;
    printf("a = %d, b = %d\n", a, b);

    b = -4;
    a = b;
    printf("a = %d, b = %d\n", a, b);

    a = 10;
    b = a;
    printf("a = %d, b = %d\n", a, b);

    b = 0;
    printf("b = %d\n", b);

    system("pause");
    return 0;
}

1.3.8三目運算子功能增強

三目運算子在C和C++編譯器的表現

int main()
{
    int a = 10;
    int b = 20;

    //返回一個最小數 並且給最小數賦值成3
    //三目運算子是一個表示式 ,表示式不可能做左值
    (a < b ? a : b )= 30;

    printf("a = %d, b = %d\n", a, b); 

    system("pause");

    return 0;
}

2結論

1)C語言返回變數的值 C++語言是返回變數本身

C語言中的三目運算子返回的是變數值,不能作為左值使用

C++中的三目運算子可直接返回變數本身,因此可以出現在程式的任何地方

2)注意:三目運算子可能返回的值中如果有一個是常量值,則不能作為左值使用(a < b ? 1 :b )= 30;

3)C語言如何支援類似C++的特性呢?

====>當左值的條件:要有記憶體空間;C++編譯器幫助程式設計師取了一個地址而已

思考:如何讓C中的三目運演算法當左值呢?

1.4 C/C++中的const

1 const基礎知識(用法、含義、好處)


int main()
{
const int a;
int const b;

const int *c;
int * const d;
const int * const e ;

return 0;
}

Int func1(const )
初級理解:const是定義常量==》const意味著只讀
含義:
//第一個第二個意思一樣 代表一個常整形數
//第三個 c是一個指向常整形數的指標(所指向的記憶體資料不能被修改,但是本身可以修改)
//第四個 d 常指標(指標變數不能被修改,但是它所指向記憶體空間可以被修改)
//第五個 e一個指向常整形的常指標(指標和它所指向的記憶體空間,均不能被修改)
Const好處
//合理的利用const,
//1指標做函式引數,可以有效的提高程式碼可讀性,減少bug;
//2清楚的分清引數的輸入和輸出特性
int setTeacher_err( const Teacher *p)
Const修改形參的時候,在利用形參不能修改指標所向的記憶體空間

2 C中“冒牌貨”

int main()
{
    const int a = 10;
    int *p = (int*)&a; 
    printf("a===>%d\n", a);
    *p = 11;
    printf("a===>%d\n", a);

    printf("Hello......\n");
    return 0;
}
解釋:
C++編譯器對const常量的處理
當碰見常量宣告時,在符號表中放入常量 =問題:那有如何解釋取地址
編譯過程中若發現使用常量則直接以符號表中的值替換
編譯過程中若發現對const使用了extern或者&操作符,則給對應的常量分配儲存空間(相容C)
?聯想: int &a = 1(err) & const int &a = 10(ok)?

C++中const符號表原理圖

1337433-550139a1f50ab58d.png
圖1-2.png

注意:

C++編譯器雖然可能為const常量分配空間,但不會使用其儲存空間中的值。

結論:
C語言中的const變數
C語言中const變數是隻讀變數,有自己的儲存空間
C++中的const常量
可能分配儲存空間,也可能不分配儲存空間
當const常量為全域性,並且需要在其它檔案中使用
當使用&操作符取const常量的地址

3 const和#define相同之處

//練習 解釋為什麼
//#define N 10 
int main()
{
    const int a = 1; 
    const int b = 2; 
    int array[a + b ] = {0};
    int i = 0; 
        
    for(i=0; i<(a+b); i++)
    {
        printf("array[%d] = %d\n", i, array[i]);
    }
    
    
    getchar();
    
    return 0;
}

C++中的const修飾的,是一個真正的常量,而不是C中變數(只讀)。在const修飾的常量編譯期間,就已經確定下來了。

4 const和#define的區別

/*對比加深
C++中的const常量類似於巨集定義
const int c = 5; ≈ #define c 5
C++中的const常量與巨集定義不同
const常量是由編譯器處理的,提供型別檢查和作用域檢查 
巨集定義由前處理器處理,單純的文字替換
//在func1定義a,在func2中能使用嗎?
//在func1中定義的b,在func2中能使用嗎?
*/

void fun1()
{
    #define a 10
    const int b = 20;
    //#undef a  # undef
}

void fun2()
{
    printf("a = %d\n", a);
    //printf("b = %d\n", b);
}

int main()
{
    fun1();
    fun2();
    return 0;
}


5 結論

C語言中的const變數

C語言中const變數是隻讀變數,有自己的儲存空間

C++中的const常量

可能分配儲存空間,也可能不分配儲存空間

當const常量為全域性,並且需要在其它檔案中使用,會分配儲存空間

當使用&操作符,取const常量的地址時,會分配儲存空間

當const int &a = 10; const修飾引用時,也會分配儲存空間

相關文章