C++_01_入門

weixin_33896726發表於2016-02-02

一、類的定義
Person.h類宣告

Person.cpp類實現

main.cpp主函式

二、名稱空間的使用


Xcode格式化程式碼:快捷鍵ctrl + i

主函式:


三、類的繼承
父類Person


子類Girl

 Java PHP中使用關鍵定extends

 c++冒號表示繼承,Objective-C一樣

 冒號後面的public表示,繼承過來的東東公開



主函式main.cpp

四、構造和析構方法
類Object


main.cpp主函式

五、執行父類的【構造方法
父類Person


子類Girl

//呼叫父類的構造方法 cpp是通過冒號實現

// JavaObjective-C是通過superkeyword

// PHP使用parentkeyword


main.cpp主函式

六、呼叫父類的方法
C++因為沒有superkeyword,因此,通過【父類名::方法()】呼叫某個父類的方法

C++還能夠指定呼叫哪一級父類的方法

// 因為c++沒有superkeyword,所以呼叫父類的方法:用的是【父類名::方法()

// 優點就是,無論有多少重繼承,都能夠通過父類名去指定呼叫某一級的父類的方法。

因此,比Java中的superkeyword要強大


父類Person


子類Girl


七、實函式、虛擬函式、純虛擬函式、函式過載

C++中,因為父類和子類都實現了cry方法【實函式】,

因此,僅僅會呼叫父類的cry方法

    假設,想要實現Java中的多型效果,

    那麼必須把【父類和子類】的cry方法所實用virtualkeyword宣告為【虛擬函式】


另外,C++純虛擬函式,類似Java中的抽象方法,由不同的子類去實現

父類Person


子類 Girl


main.cpp主函式
當父類和子類 都實現了【實函式cry】時的情況:直接呼叫父類的cry

當父類和子類的cryy方法都用【virtual】keyword宣告時。
與Java多型一樣,呼叫子類的方法

純虛方法

// 純虛擬函式,類似Java中的抽象方法,由不同的子類去實現

virtual void hobby()=0;


八、C++中的類。假設全部方法全是純虛擬函式,那麼就是純虛類;
相當於Java中的介面。因為C++本身支援多繼承。因此,在使用時,儘量依照Java中的【單繼承實現多介面原則】,將其它父類設計成【純虛類】
九、函式過載,即名稱一樣,引數列表不同
C++的string型別 不用加*

十、運算子過載

// 過載 += 運算子

    voidoperator+=(Point other){

       add(other);

    };


返回值operator運算子(引數列表){};


通過物件例項(或結構體)訪問,使用【.】
通過指標訪問  使用【->】
Point類

主函式main.cpp


使用指標,->,解引用

十一、偽函式
像函式一樣呼叫,但不是函式,實質為:類或結構體
優點:能夠將一些程式碼段,當作 一個類的物件例項,進行傳遞;如:作為方法回撥,

十三、C++引用 &  【經常使用於引數列表中】
避免不必要的記憶體拷貝操作

十四、C++友元類
作用:將類中private成員,公開給特定的類【友元類】
由於不太好操控,so,Java語言就沒有此概念
C++中,訪問修飾符 預設就是:pravite
【在A類內部使用keywordfriend class Foo;】宣告友元類
此時,Foo類就能夠訪問A類中的私有成員(耦合度太高)

十七、檔案操作
右擊products,show in finder,能夠看到輸出的文字檔案
使用ofstream輸出到檔案1.txt


使用ifstream讀入debug資料夾下的1.txt

使用ifstream讀入debug資料夾下的1.txt
stringbuf類 代表緩衝區;定義在標頭檔案<sstream>中

<span style="font-size:14px;">//
//  main.cpp
//  17_檔案操作
//
//  Created by beyond on 14-10-2.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#include <iostream>
// 檔案操作 引入標頭檔案 fstrem 即檔案流
#include <fstream>
// 使用stringbuf字元緩衝區
#include <sstream>

using namespace std;

void testOutput(){
    // 關聯1.txt
    ofstream stream("1.txt");
    stream<<"Hello Beyond";
    // 最後一定要記得關閉流
    stream.close();
    
    
    std::cout << "\n >>>> end output<<<<\n";
}

void testReadOneChar(){
    // 使用輸入流
    ifstream input("1.txt");
    // 快取
    char c;
    input>>c;
    // 最後一定要記得關閉流
    input.close();
    printf("%c",c);
    
}
void testReadToConsole(){
    // 使用輸入流
    ifstream input("1.txt");
    // 快取
    stringbuf buf;
    // 讀入緩衝區
    input>>&buf;
    // 最後一定要記得關閉流
    input.close();
    std::cout << buf.str() << "\n >>>> end <<<<\n";
}
int main(int argc, const char * argv[])
{
    // testOutput();
    // testReadOneChar();
    testReadToConsole();
    return 0;
}</span>



十六、C++字串

C++字串包裝成一個類 string;過載了運算子 += 僅僅能接收字串

匯入<sstream>後,能夠使用類stringstream

可連線不同型別的變數,

由於,它過載了運算子 << 

所以,能夠連線不同型別

而且返回值是stream本身,因此,可連續<<

呼叫它str()方法,返回c++字串

繼續呼叫c_str()方法,返回C字串


C++ API 引數線上地址

string類的c_str()方法

stringstream類


stringstream類的str()方法

十五、C++標準容器庫container
注意迭代器是一個內部類,它的物件例項是一個指標,
在對list取value時,使用【*】解引用
在對map取key或value時,使用時【->】
list有序集合的使用和遍歷

map字典的使用和遍歷
為方便使用map,過載了操作符【】

C++API線上參考


十二、C++函式指標 僅僅是多了一個型別限定

void (Animal::*funcPointer)();


typedef void(Animal::*FuncPoint)();

定義一個型別,一個函式指標型別;

函式指標,指向的函式必須是Animal或它子類裡面的函式,而且沒有引數,返回值是void

相比較c中的函式指標,僅僅是多一個型別限定:必須是Animal或它子類裡面的函式



通過執行緒+函式指標+sleep,達到延時3秒後執行目的
效果圖:

main.cpp程式碼:
//
//  main.cpp
//  12_函式指標_2_延時執行
//
//  Created by beyond on 14-10-3.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#include <iostream>
// 執行緒
#include <thread>
// sleep
#include <unistd.h>
// 使用名稱空間
using namespace std;
// 提前宣告類
class Animal;
// 定義一個型別,一個函式指標型別;函式指標,指向的函式 必須是Animal或它子類裡面的函式,而且沒有引數
// 相比較c中的函式指標,僅僅是多一個型別限定:必須是Animal或它子類裡面的函式
typedef void(Animal::*FuncPoint)();

// 執行緒的構造方法 中用到的 引數:實質是一個要執行的函式 相當於執行緒啟動後,要執行的任務,相當於Java中的run方法
void run(Animal *target,FuncPoint pointer,int delay){
    // 執行緒啟動後,真正的要執行的方法,任務程式碼
    // 1.先sleep
    sleep(delay);
    // 2.執行target的pointer所指向的方法
    // 先對函式指標 解引用後,取得函式體,通過物件target執行函式
    (target->*pointer)();
};

// 定義一個延時執行 特定target的特定selector的函式
void perform_delay(Animal *target,FuncPoint pointer,int delay){
    // 呼叫thread類 來執行target物件的 pointer所指向的方法,並延時delay秒
    // 前一個引數 是要執行的方法,後面全是 填充方法的引數列表
    thread t(run,target,pointer,delay);
    // thread的join方法,會線上程被真正地全然執行後,才返回
    t.join();
}



class Animal {
public:
    // 定義一個成員變數 型別是一個函式指標
    FuncPoint p;
};
// 繼承自Animal
class Bird :public Animal{
public:
    // 構造方法,在構造方法中,呼叫 成員方法
    Bird(){
        // 1、正常方式:能夠直接呼叫成員方法
        this->fly();
        // 2、特殊方式:通過 一個函式指標,呼叫 成員方法...
        // &Bird::fly表示 取成員方法的 地址
        // (FuncPoint) 表示 強制轉換成 一個函式指標型別
        p = (FuncPoint)(&Bird::fly);
        // 最後,通過函式指標,解引用 變成函式,通過this-> 呼叫 函式
        (this->*p)();
        // 3、延時3秒後 執行,自已的成員方法
        FuncPoint point = (FuncPoint)(&Bird::fly);
        perform_delay(this, point, 3);
    }
    // 成員方法
    void fly(){
        printf("我是一僅僅小小小小小鳥~\n");
    };
};


int main(int argc, const char * argv[])
{
    std::cout << ">>>> start <<<<\n";    
    Bird *b = new Bird();
    delete b;
    
    std::cout << ">>>> end <<<<\n";
    return 0;
}





C++中的vector

vector類為內建陣列提供了一種替代表示。與string類一樣 vector 類是隨標準 C++引入的標準庫的一部分 。為了使用vector 我們必須包括相關的標頭檔案  :

#include <vector>

使用vector有兩種不同的形式。即所謂的陣列習慣和 STL習慣

一、陣列習慣使用方法

1. 定義一個已知長度的 vector :

vector< int > ivec( 10 );  //類似陣列定義int ia[ 10 ];

能夠通過ivec[索引號] 來訪問元素

使用 if ( ivec.empty() ) 推斷是否是空,ivec.size()推斷元素個數。

 

2. vector的元素被初始化為與其型別相關的預設值:算術和指標型別的預設值是 0。對於class 型別,預設值可通過呼叫這類的預設建構函式獲得,我們還能夠為每一個元素提供一個顯式的初始值來完畢初始化,比如  
vector< int > ivec( 10, -1 ); 
定義了 ivec 它包括十個int型的元素 每一個元素都被初始化為-1 

對於內建陣列 我們能夠顯式地把陣列的元素初始化為一組常量值,比如 : 
int ia[ 6 ] = { -2, -1, 0, 1, 2, 1024 };


我們不能用相同的方法顯式地初始化 vector ,可是能夠將 vector 初始化為一個已有陣列的所有或一部分,僅僅需指定希望被用來初始化 vector 的陣列的開始地址以及陣列最末元的下一位置來實現,比如:  
// 把 ia 的 6 個元素複製到 ivec 中 
vector< int > ivec( ia, ia+6 );
  


被傳遞給ivec 的兩個指標標記了用來初始化物件的值的範圍。第二個指標總是指向要拷貝的末元素的下一位置,標記出來的元素範圍也能夠是陣列的一個子集,比如 :

// 拷貝 3 個元素 ia[2], ia[3], ia[4] 
vector< int > ivec( &ia[ 2 ], &ia[ 5 ] );


3. 與內建陣列不同 vector 能夠被還有一個 vector 初始化 或被賦給還有一個 vector 比如  
vector< string > svec; 
void init_and_assign() 

    // 用還有一個 vector 初始化一個 vector 
    vector< string > user_names( svec ); 
    // ... 
 
    // 把一個 vector 拷貝給還有一個 vector 
    svec = user_names; 
}

 

二、STL習慣使用方法

在 STL9中對vector 的習慣使用方法全然不同。我們不是定義一個已知大小的 vector,而是定義一個空 vector  
vector< string > text;


1. 我們向 vector 中插入元素。而不再是索引元素,以及向元素賦值,比如 push_back()操作,就是在 vector 的後面插入一個元素以下的 while 迴圈從標準輸入讀入一個字串序列並每次將一個字串插入到 vector 中  
string word; 
while ( cin >> word ) { 
text.push_back( word ); 
// ... 
}

儘管我們仍能夠用下標操作符來迭代訪問元素  
cout << "words read are: \n"; 
 
for ( int ix = 0; ix < text.size(); ++ix ) 
      cout << text[ ix ] << ' '; 
 
cout << endl; 
可是 更典型的做法是使用 vector 操作集中的begin()和 end()所返回的迭代器 iterator  
對 :
cout << "words read are: \n"; 
 
for ( vector<string>::iterator it = text.begin(); 
    it != text.end(); ++it ) 
           cout << *it << ' '; 
 
cout << endl 
iterator 是標準庫中的類,它具有指標的功能 


*it; 
對迭代器解引用,並訪問其指向的實際物件  
++it;

向前移動迭代器 it 使其指向下一個元素  

2. 注意 不要混用這兩種習慣使用方法。 比如,以下的定義  
vector< int > ivec; 
定義了一個空vector 再寫這種語句  
ivec[ 0 ] = 1024; 
就是錯誤的 。由於 ivec 還沒有第一個元素。我們僅僅能索引 vector 中已經存在的元素 size()操作返回 vector 包括的元素的個數 。

3. 類似地 當我們用一個給定的大小定義一個 vector 時,比如  :
vector<int> ia( 10 ); 
不論什麼一個插入操作都將新增vector 的大小,而不是覆蓋掉某個現有的元素。這看起來好像是非常顯然的,可是 以下的錯誤在剛開始學習的人中並不少見 :
const int size = 7; 
int ia[ size ] = { 0, 1, 1, 2, 3, 5, 8 }; 
vector< int > ivec( size ); 
 
for ( int ix = 0; ix < size; ++ix ) 
    ivec.push_back( ia[ ix ]); 
程式結束時ivec 包括 14 個元素, ia 的元素從第八個元素開始插入。