安卓NDK開發-C++筆記

c++最難的就是內存和指針

1、學習內容

數據類型,數組,內存佈局,物理內存,虛擬內存。

 

內存的概念:app內存。兩個角度

(1、硬件角度:內存是計算機必不可少的一個組成部分,是與CPU溝通的橋樑,計算機中所有的程序都是運行在內存中,例如內存條)

(2、邏輯角度:內存是一塊具備隨機訪問能力,支持讀、寫操作,用來存放程序及程序運行中產生數據的區域)

內存的單位

位(bit)是電子計算機中最小的數據單位,每一位的狀態只能是0或1。字節(Byte):1Byte = 8bit,是內存基本的計量單位。

內存的編址

計算機中的內存按字節編址,每個地址的儲存單位可以存放一個字節(8個bit)的數據,CPU通過內存地址獲取指令和數據,並不關心這個地址所代表的空間具體在什麼位置,怎麼分佈,因爲硬件的設計保證一個地址對應着一個固定的空間,所以說:內存地址和地址指向的空間共同構成一個內存單元。

內存的地址:在java中指的是對象的引用,內存地址通常用十六進制的數據表示,指向內存中的某一塊區域。

內存地址的分配規則,是連續的,一個挨着一個,當對象需要申請內存時,先給這個對象分配一個編碼,這個編碼就是內存地址。

內存對象和內存地址的區別

基本數據類型,c和java的long類型。c4個,java8個

內存的組成

基礎函數

Android內存組成

C語言內存組成

BSS段-存放全局變量

數組和指針,數組指針,指針數組

指針數組,每一個數組都是一個指針地址

指針的優先級

定義: () > []  > *

 

數組指針(也稱爲行指針)

定義:int (*p)[n]

優先級高,首先說明p是一個指針,指向一個整形的一維數組,這個一維數組的長度是n,也可以說是p的步長,也就是說執行p+1時,p要跨過n個整形數組的長度。

 

 

結構體共同體

使用struct關鍵字來定義

結構體大小:當結構體需要內存過大,使用動態內存申請。結構體佔用字節數和結構體內字段有關,指針佔用內存就是4/8字節,因此傳指針比傳值效率更高。

內存對齊:對齊跟數據在內存中的位置有關。如果一個變量的內存地址正好位於它長度的整數倍,他就被稱作自然對齊,比如在32位cpu下,假設一個整形變量的地址爲0x00000004那它就是自然對齊。

 

結構體儲存原則:(1)、結構體變量中成員的偏移量必須是成員大小的整數倍(0是任意數的整數倍)

(2)、結構體大小必須是所有成員大小的整數倍,也即所有成員大小的公倍數。

 

共用體:共用體是一種特殊的數據類型,允許您在相同的內存位置儲存不同的數據類型。你可以定義一個帶有多成員的共用體,但是任何時候只能由一個成員帶有值。共用體提供了一種使用相同的內存位置有效方式。

共用體的使用

union Data{

    int i;

    float f;

    char str[20];

}data;

共用體大小取決於,共用體中最長的那個變量大小

so動態庫和編譯

比如反編譯,安全。

定義:在windows平臺和linux平臺下都大量存在着庫。Android中也存在庫,庫顧名思義,指的是一個容器文件,裏面裝的是函數。

由於win和linux的平臺不同,主要是編譯器,彙編器和連接器不同,因此二者庫的二進制是不兼容的。

庫存在的意義:庫是別人寫好現有的,成熟的,可以複用的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都是從零開始,因此庫存在的意義非同尋常。.dll)和靜態庫(.lib)在安卓平臺下動態庫(.so)靜態庫(.a)

動態庫和靜態庫的區別

靜態庫文件比較大,動態庫比較小

靜態庫需要在編譯時被鏈接在目標代碼中,動態庫在運行時纔會被加載到目標代碼中

靜態庫類似於android中的module,一旦打包APK需要重新編譯

動態庫類似於jar包,打包是不需要重新進行編譯

通過gcc編譯動態庫,gcc test.c -fPIC -shared -o test.so

通過gcc編譯靜態庫,gcc test.c -fPIC -static -o test.so

二、類的構造和析構、友元函數

構造,類被創建的時候執行

析構,類被銷燬的時候執行

友元函數,需要暴露給別人修改本類屬性的時候友好

單例模式:

#pragma once
class Student {
private:
              static Student* instance;
       
public:
       static Student* getInstance(void);
};
#include "Student.h"
Student* Student::instance = 0;
Student* Student::getInstance(void) {
       if (!instance) {//如果等於0,非0就是真,代表instance沒有被初始化
              instance = new Student();
       }
       return instance;
}
// Instance.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
#include <iostream>
#include "Student.h"
#include "Test.h"
//操作符重載
int main()
{
       Student* student = Student::getInstance();
    std::cout << "Hello World!\n";
       Test test1;
       test1.i = 100;
       Test test2;
       test2.i = 200;
       Test test3 = test1 + test2;
       std::cout << test3.i;
}
#pragma once
class Test
{//操作符重載
public:
       int i;
       Test operator+(const Test& t) {
              Test temp;
              temp.i = this->i + t.i;
              return temp;
       }
};

 

繼承多態

靜態多態:

編譯的時候確認的類型

動態多態:

運行時調用真正對象的函數

虛函數 動態多態,經過virtual修飾。就是虛函數。

注意:構造函數永遠不要設爲虛函數,析構方法聲明爲虛函數

#pragma once
class Parent {
public:
       virtual void test() {
              std::cout << "Parent" << std::endl;
       }
};
class Parent1 {
public:
       void test() {
              std::cout << "Parent1" << std::endl;
       }
};
class Child : public Parent,Parent1{
public :
       void test() {
              //Parent::test();
              std::cout << "Child" << std::endl;
       }
};
#include <iostream>
#include "Extends.h"
int main()
{
       /*Child child;
       child.test();*/
       Parent* child = new Child();
       child->test();
    std::cout << "Hello World!\n";
}

 

泛型編程

#include <iostream>
//泛型模板,模板編程
//函數模板,Java的泛型方法
template <typename T>
T a(T i, T j) {
       return i > j ? i : j;
}
//類模板,
template <class T,class E>
class Q {
public:
       T test(T t, E e) {
              return t + e;
       }
};
int main()
{
       Q<int, float> q;
       std::cout << q.test(1,1.1f);
    std::cout << "Hello World!\n";
}

 

類型轉換

C++風格的類型轉換提供了4種類型的轉換操作來應對不同場合的應用

在C++中const相當於java中的final

強轉類型:1、const_cast字面上理解就是去強轉const屬性。2、static_cast,命名上理解是靜態類型強轉,如int轉char。3、dynamic_cast,命名上理解是動態類型轉換,如子類和父類之間的多態類型轉換。4、reinterpret_cast,僅僅重新解釋類型,但沒有進行二進制的轉換。

 

容器

C++中有兩種容器,

序列式容器:元素排列順序與元素本身無關,是由添加順序所決定的

java中,stack棧。而

c++有  vector,list,dequeue,queue,stack,priority queue;

以vector(向量容器)爲例子

 //向量容器
       vector<int> vec_1;
       //聲明有一個元素空間
       vector<int> vec_2(1);
       //6個元素,值都爲1
       vector<int> vec_3(6, 1);
       vector<int> vec_4(vec_3);
       vec_1.push_back(100);
       cout << "通過下標取得元素:" << vec_1[0] << endl;
       vec_1.front();//取得隊前
       vec_1.back();//取得隊尾
       //vec_1.clear();//清除
       //vec_1.erase(vec_1.begin(), vec_1.end());//清除某一區域的數據
       cout << "獲得vec的容器大小:" << vec_1.capacity() << endl;

 

關聯式容器:

Set Map

//關聯式容器
       //set集合元素不可重複
       set<int> set1 = { 1,2,3,4,5,10 };
       set1.insert(134);//添加
       pair<set<int>::iterator, bool> _pair = set1.insert(100);
       cout << "set裏面有:" << set1.size() << endl;
       //cout << "set的pair:" <<  << endl;
       set<int>::iterator itt = set1.begin();
       set1.end();//指向最後一個元素的下一個元素
       for (; itt != set1.end(); itt++) {
              cout << *itt << endl;
       }
       //map
       map<int, string> map1;
       map<int, string> map2 = { {1,"E"},{2,"B"} };
       map2.insert({ 3,"F" });
       map2[3] = "Y";
       map<int, string>::iterator mapp = map2.begin();
       for (; mapp != map2.end(); mapp++) {
              cout << mapp->first<<"=="<<mapp->second << endl;
       }

 

這兩種容器都是在stl:標準模板庫裏面;

 

命名空間

namespace first_space {
       void func() {
              cout << "第一個" << endl;
       }
}
namespace second_space {
       void func() {
              cout << "第二個命名空間" << endl;
       }
}
int main()
{
       //調用第一個
       first_space::func();
       //調用第二個
       second_space::func();
}

 

引用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章