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();
}
引用