【6.C++基礎】代碼常識

返回數組的形式

直接return array只會返回第一個元素哦!下面介紹四種返回數組方法ios

#include <iostream>
#include <string.h>
#include <math.h>

#define CITY_NUM 11000
class LbsIndexCity{
public:
    LbsIndexCity(int city_id):m_city_id(city_id){}
    int get_city_id(){
        return m_city_id;
    }
private:
    int m_city_id;
};
LbsIndexCity* m_city[CITY_NUM];

void add_m_city(int city_id){
    m_city[101]=new LbsIndexCity(city_id);
}
/*
1.
LbsIndexCity* (* get_m_city())[CITY_NUM]{
    return &m_city;
}
*/

/*
2.
typedef LbsIndexCity* arrT[CITY_NUM];
arrT * get_m_city(){
    return &m_city;
}
*/
/*
3.
auto get_m_city() -> LbsIndexCity*(*)[CITY_NUM]{
    return &m_city;
}
*/

LbsIndexCity* arrT[CITY_NUM]={nullptr};

decltype(arrT) *get_m_city(){
    return &m_city;
}


int main() {
    add_m_city(1001);
    LbsIndexCity* (*m_city)[CITY_NUM] = get_m_city();
    for(int city_id =0; city_id < CITY_NUM; city_id++) {
        if((*m_city)[city_id] == NULL){
            continue ;
        }else{
            std::cout <<(*m_city)[city_id]->get_city_id()<<std::endl;
        }
    }
    std::cout << "cyy,Hello, World!" <<std::endl;
    return 0;
}

單例

1.餓漢實現數組

/*餓漢實現
 * 因爲要進行線程同步,因此在訪問量比較大,或者可能訪問的線程比較多時,採用餓漢實現,能夠實現更好的性能。這是以空間換時間
 * 顯示調用Destroy
 * */

template <class T>
class singleton{
private:
    static T* p;
    singleton(){}
    ~singleton(){}
public:
    static T* GetInstance();
    static void Destroy();  //須要在退出時顯示調用


};
template <class T>
T* singleton<T>::p = new T();

template <class T>
T* singleton<T>::GetInstance(){
    return p;
}
template <class T>
void singleton<T>::Destroy(){
    if(p == nullptr){
        return ;
    }
    std::cout<<"delete~"<<std::endl;
    delete p;
}

2.懶漢實現 pthread_once,atexit(Destroy);多線程

#include "pthread.h"
#include <stdlib.h>
#include <iostream>
/*懶漢實現
 * 在訪問量較小時,採用懶漢實現,不到萬不得已就不會去實例化類,也就是說在第一次用到類實例的時候纔會去實例化
 * 顯示調用析構
 * */
template <class T>
class singleton2
{
protected:
    singleton2(){};
private:
    singleton2(const singleton2&){};
    singleton2& operator=(const singleton2&){};
    static T* m_instance;
    static pthread_once_t m_once;
    //static pthread_mutex_t g_mutex;

public:
    static void Init();
    static void Destroy();
    static T* GetInstance();
};
template <class T>
void singleton2<T>::Destroy(){
    if(m_instance == nullptr){
        return ;
    }
    delete m_instance;
}
template <class T>
void singleton2<T>::Init()
{
    m_instance = new T();
    atexit(Destroy);
}

template <class T>
T* singleton2<T>::GetInstance()
{
    pthread_once(&m_once,Init);
    return m_instance;
}

template <class T>
pthread_once_t singleton2<T>::m_once = PTHREAD_ONCE_INIT;

template <class T>
T* singleton2<T>::m_instance = NULL;

2.懶漢實現 鎖,atexit(Destroy);函數

template <class T>
class singleton2
{
protected:
    singleton2(){};
private:
    singleton2(const singleton2&){};
    singleton2& operator=(const singleton2&){};
    static T* m_instance;
    static pthread_once_t m_once;
    //static pthread_mutex_t g_mutex;

public:
    static void Init();
    static void Destroy();
    static T* GetInstance();
};
template <class T>
void singleton2<T>::Destroy(){
    if(m_instance == nullptr){
        return ;
    }
    delete m_instance;
}

template <class T>
T* singleton2<T>::m_instance = NULL;

template <class T>
pthread_mutex_t singleton2<T> ::g_mutex = PTHREAD_MUTEX_INITIALIZER;

template <class T>
T* singleton2<T>::GetInstance()
{
    if( m_instance == NULL)
    {
        pthread_mutex_lock(&g_mutex);
        if( m_instance == NULL)
        {
            T* ptmp = new T();
            m_instance = ptmp;   //防止多線程順序
            atexit(Destroy)
        }
        pthread_mutex_unlock(&g_mutex);
    }
    return m_instance;
}

4.懶漢 靜態對象,保證只有一個,不用new,不須要析構性能

template <class T>
class singleton3
{
protected:
    singleton3(){};
private:
    singleton3(const singleton3&){};
    singleton3& operator=(const singleton3&){};
    static pthread_mutex_t g_mutex;
public:
    static T* GetInstance();
};
template <class T>
T* singleton3<T>::GetInstance() {
    pthread_mutex_lock(&g_mutex);
    static T _instance;
    pthread_mutex_unlock(&g_mutex);
    return &_instance;
}
template <class T>
pthread_mutex_t singleton3<T> ::g_mutex = PTHREAD_MUTEX_INITIALIZER;

5.測試函數測試

#include "pthread.h"
#include <stdlib.h>
#include <iostream>
class ApplicationImpl
{

public:
    ApplicationImpl()
    {
        std::cout << "ApplicationImpl ..." << std::endl;
    }

    ~ApplicationImpl()
    {
        std::cout << "~ApplicationImpl ..." << std::endl;
    }

    void Run()
    {
        std::cout << "Run ..." << std::endl;
    }
};
    typedef singleton3 < ApplicationImpl > Application;

    void *routine(void *arg)
    {
        Application::GetInstance()->Run();
    }


int main(void)
    {
        Application::GetInstance()->Run();

        pthread_t tid;
        int ret;
        if ((ret = pthread_create(&tid, NULL, routine, NULL)) != 0)
        {
            fprintf(stderr, "pthread create: %s\n", strerror(ret));
            exit(EXIT_FAILURE);
        }

        Application::GetInstance()->Run();

        pthread_join(tid, NULL);
        // Application::Destroy(); //第一個須要顯示調用

        return 0;
    }

以上程序的幾點說明:
1.靜態成員與類自己相關,不是對象(成員函數不能聲明const,不能用this指針)。可用返回類類型,普通只能是類&或類*,可以使用靜態成員做爲默認實參
2.在類外部定義靜態成員不能重複static關鍵字
3.靜態成員函數能夠在類內/外定義(內部是內聯的)
靜態成員不是構造函數初始化的,通常再也不內部初始化,const類型須要在內部初始化時,也應該在類外部定義下
4.const未初始化的,要在構造函數顯示初始化
5.A a;默認構造函數,不需手動事發昂,析構函數自動執行
A= New A(); 只有delete釋放,堆,一次初始化屢次使用,可作返回等,不適合頻繁調用
A* a=NULL; 普通指針,未通過初始化,不需delete
模板:優化

禁止繼承的類

經過友元+虛繼承實現。F是N的友元,能夠調用N的私有初始化函數,F能夠構造,若M要繼承F,因爲F是虛繼承,裏邊直接包含N的虛表,會直接調用N的構造函數爲private報錯。若F不是虛繼承,F的函數內會綁定N的構造函數在F內,友元能夠調用this

template<typename T>
class NoneInherit {
    friend T;
private:
    NoneInherit() {
    }
    ~NoneInherit() {
    }
};

class Finalclass: virtual public NoneInherit<Finalclass> {
public:
    Finalclass() {
    }
    ~Finalclass() {
    }
};

虛函數/虛繼承

虛函數

若用基類指針,賦值子類對象的方法調用,對於沒有聲明被聲明成虛函數的方法,代碼中的調用在編譯時就已經被綁定了實現,綁定的是基類的實現。虛函數會增長一個vftable虛函數表,在動態運行時調用(注意只有在用過指針和引用時才須要動態綁定)。線程

內聯函數是在編譯時期展開,而虛函數的特性是運行時才動態聯編,因此二者矛盾,不能定義內聯函數爲虛函數。
構造函數需在編譯時刻,由於需構造出個對象,才能執行動做。因此不能將構造函數定義爲虛函數。virtual意味着派生類能夠改寫其動做。派生類的構造函數會先執行基類的構造函數而不是取代基類構造函數
靜態成員函數屬於一個類而非某一對象,沒有this指針,它沒法進行對象的判別。
虛析構函數和其餘虛函數同樣高指針

虛函數和重載函數。
在基類中用關鍵詞「virtual」聲明成員函數,而後在派生類中正式定義或從新定義此函數,其中要求函數名、函數類型、參數類型和個數必須與基類虛函數相同。
函數重載在同一做用域(如:類)中,幾個函數名字相同但參數列表(參數類型,參數個數)不全相同。針對某個類裏面的同名函數而言,而虛函數是針對基類和派生類之間同名函數而言。
在同一類族中不能再定義一個非virtual的但與虛函數具備相同參數(類型和個數)和返回類型的同名函數。

純虛函數 double xx() const=0;抽象基類,不能建立對象

虛繼承

若出現菱形繼承,D->B虛繼承,C虛繼承->A,D會由於B,C共同繼承A有公共的一些成員變量和方法是相同的。若是用A指針指向D類的實例,則對於共同的成員變量和方法,編譯器沒法判斷是要使用B類中的仍是使用C類中的。增長虛指針,與虛函數處理思想同樣,和虛函數自己不要緊。
非虛繼承

class LandAnimal    size(12):
1>      +---
1>   0  | +--- (base class Animal)
1>   0  | | {vfptr}
1>   4  | | name
1>      | +---
1>   8  | numLegs
1>      +---
1>
1>  LandAnimal::$vftable@:
1>      | &LandAnimal_meta
1>      |  0
1>   0  | &Animal::breathe
1>   1  | &LandAnimal::run
1>
1>  class Mammal    size(12):
1>      +---
1>   0  | +--- (base class Animal)
1>   0  | | {vfptr}
1>   4  | | name
1>      | +---
1>   8  | numBreasts
1>      +---
1>
1>  Mammal::$vftable@:
1>      | &Mammal_meta
1>      |  0
1>   0  | &Animal::breathe
1>   1  | &Mammal::milk
1>
1>  class Human size(28):
1>      +---
1>   0  | +--- (base class Mammal)
1>   0  | | +--- (base class Animal)
1>   0  | | | {vfptr}
1>   4  | | | name
1>      | | +---
1>   8  | | numBreasts
1>      | +---
1>  12  | +--- (base class LandAnimal)
1>  12  | | +--- (base class Animal)
1>  12  | | | {vfptr}
1>  16  | | | name
1>      | | +---
1>  20  | | numLegs
1>      | +---
1>  24  | race
1>      +---
1>
1>  Human::$vftable@Mammal@:
1>      | &Human_meta
1>      |  0
1>   0  | &Animal::breathe
1>   1  | &Human::milk
1>
1>  Human::$vftable@LandAnimal@:
1>      | -12
1>   0  | &Animal::breathe
1>   1  | &Human::run

虛繼承:

1>  class LandAnimal    size(20):
1>      +---
1>   0  | {vfptr}
1>   4  | {vbptr}
1>   8  | numLegs
1>      +---
1>      +--- (virtual base Animal)
1>  12  | {vfptr}
1>  16  | name
1>      +---
1>
1>  LandAnimal::$vftable@LandAnimal@:
1>      | &LandAnimal_meta
1>      |  0
1>   0  | &LandAnimal::run
1>
1>  LandAnimal::$vbtable@:
1>   0  | -4
1>   1  | 8 (LandAnimald(LandAnimal+4)Animal)
1>
1>  LandAnimal::$vftable@Animal@:
1>      | -12
1>   0  | &Animal::breathe
1>
1>  class Mammal    size(20):
1>      +---
1>   0  | {vfptr}
1>   4  | {vbptr}
1>   8  | numBreasts
1>      +---
1>      +--- (virtual base Animal)
1>  12  | {vfptr}
1>  16  | name
1>      +---
1>
1>  Mammal::$vftable@Mammal@:
1>      | &Mammal_meta
1>      |  0
1>   0  | &Mammal::milk
1>
1>  Mammal::$vbtable@:
1>   0  | -4
1>   1  | 8 (Mammald(Mammal+4)Animal)
1>
1>  Mammal::$vftable@Animal@:
1>      | -12
1>   0  | &Animal::breathe
1>
1>  class Human size(36):
1>      +---
1>   0  | +--- (base class Mammal)
1>   0  | | {vfptr}
1>   4  | | {vbptr}
1>   8  | | numBreasts
1>      | +---
1>  12  | +--- (base class LandAnimal)
1>  12  | | {vfptr}
1>  16  | | {vbptr}
1>  20  | | numLegs
1>      | +---
1>  24  | race
1>      +---
1>      +--- (virtual base Animal)
1>  28  | {vfptr}
1>  32  | name
1>      +---
1>
1>  Human::$vftable@Mammal@:
1>      | &Human_meta
1>      |  0
1>   0  | &Human::milk
1>
1>  Human::$vftable@LandAnimal@:
1>      | -12
1>   0  | &Human::run
1>
1>  Human::$vbtable@Mammal@:
1>   0  | -4
1>   1  | 24 (Humand(Mammal+4)Animal)
1>
1>  Human::$vbtable@LandAnimal@:
1>   0  | -4
1>   1  | 12 (Humand(LandAnimal+4)Animal)
1>
1>  Human::$vftable@Animal@:
1>      | -28
1>   0  | &Human::breathe

執行順序

1.在同一層次的繼承中,虛擬繼承的構造函數要先於非虛擬繼承的構造函數,在同一層的全部非虛擬繼承的類中,其構造函數的執行順序是先左後右,一樣的在同一層全部非虛擬繼承的類中,構造函數的執行也是先左後右,和類的定義順無關

class c :virtual public e, public  a, public b, virtual public d

=》e,d,a,b,c
2.類成員變量,初始化順序與定義順序一致

public:
    int a1;
    int a2;
    a(int x,int y) :a2(y),a1(x){}

=>a1,a2
3.
變量能夠分爲:全局變量、靜態全局變量、靜態局部變量和局部變量。
按存儲區域分,全局變量、靜態全局變量和靜態局部變量都存放在內存的靜態存儲區域,局部變量存放在內存的棧區。
按做用域分,全局變量在整個工程文件內都有效;靜態全局變量只在定義它的文件內有效;靜態局部變量只在定義它的函數內有效,而且程序僅分配一次內存,函數返回後,該變量不會消失;局部變量在定義它的函數內有效,可是函數返回後失效
全靜態變量,全局變量,在main以前初始化,在編譯時分配內存(類中靜態變量要在類外定義,對於const能在編譯時肯定在編譯時執行,不然同理),局部靜態變量在調用到具體函數時初始化。
4.析構函數與構造函數調用順序相反。(new 調用delete時,局部變量非靜態 函數退出後 全局變量/靜態變量(不管局部仍是全局) 程序退出時)

inline與宏

任何在類的說明部分定義的函數都會被自動的認爲是內聯函數。
宏在預編譯期間處理(字符串替換),內聯函數是編譯期間插入(省去函數棧分配);內聯函數有參數檢查等;內聯函數會插入到調用方,沒必要尋址。

volatile:cpu寄存器不優化,編譯器不優化。仍是沒辦法解決多線程指令順序。通常用於文件映射等
https://liam.page/2018/01/18/...

相關文章
相關標籤/搜索