GitHub Repo:coderZsq.github.io
Follow: coderZsq · GitHub
Resume: coderzsq.github.io/coderZsq.we…
日常扯淡
作為iOS
開發的菜雞, 平日裡的工作就是做業務, 調UI, 對於我們這種弱雞玩家來說, 程式設計呢, 其實就是調方法, 調屬性, 調庫…
但光是做業務UI的工作肯定會讓自己日漸乏味, 為了不重複寫那些看了想吐的程式碼, 去年就花了點時間寫了一個程式碼生成工具, 用於配置一鍵生成垃圾程式碼的, 這樣對於菜雞開發者也就是我來說, 只需要調調自己封裝的一些UI庫, 搭搭積木就完成工作了, 其他時間就可以自由支配玩點有趣的事情.
去年渾渾噩噩, 學了一堆有的沒的, 什麼Vue
, React
, Spring
的呼叫, 但一直這樣無所事事的我, 今年也想深入的學習一些什更深層次的東西, 而不僅僅只是在UI層的淺嘗輒止.
然而在iOS這個領域中, 想要深入研究, CC++
, 彙編
, Linux
, 像三座大山一樣攔在我面前, 所以做為菜雞的我路漫漫而其修遠兮.
本文就通過學習C++
的語法開始, 一點一點的剖析OC的本質, 直到世界的盡頭.
C++ 作者的建議
- 在C++中幾乎不需要用巨集, 用const和enum定義顯式的常量, 用inline避免函式呼叫的額外開銷, 用模板去刻畫一組函式或型別, 用namespace去避免命名衝突.
- 不要在你需要變數之前去宣告, 以保證你能立即對它進行初始化.
- 不要用malloc, new運算會做的更好.
- 避免使用void*, 指標算數, 聯合和強制, 大多數情況下, 強制型別轉換是設計錯誤的指示器.
- 儘量少用陣列和C風格的字串, 標準庫中的string和vector可以簡化程式.
- 更加重要的是, 試著將程式考慮為一組由類和物件表示的互相作用的概念年, 而不是一堆資料結構和一些可以撥弄的二進位制.
標準輸入輸出
我們先來看C++
的標準輸入輸出:
char buf[10];
scanf("%s", buf);
printf("%s
", buf);
複製程式碼
這個是大家都很熟悉的C
的輸入輸出, 也就是scanf
和printf
. 但C
語言是越界不檢的, 所以這裡的char buf[10]
的緩衝區可能會造成寫越界, 導致不安全訪問.
char buf[10];
fgets(buf, 10, stdin);
printf("%s
", buf);
複製程式碼
所以C
使用了fget
強制的截斷了輸入來保證, 訪問的安全.
12345678901234567
123456789
Program ended with exit code: 0
複製程式碼
以上是C
語言安全標準輸入的列印日誌, 我們可以看到, 由於設定了10
為輸入截斷引數, 後面就不再輸入了.
char buf[10];
cin>>buf;
cout<<buf<<endl;
複製程式碼
我們再來看看C++
的輸入流cin
和cout
, 可以看到的是, cin
操作char buf[10]
同樣不安全, 也會造成寫越界.
char buf[10];
cin.getline(buf, 10);
cout<<buf<<endl;
複製程式碼
我們可以看到, cin.getline
很好的解決了這個問題, 但其實作用和fgets
並無二異.
string buf;
cin>>buf;
cout<<buf<<endl;
複製程式碼
然而使用string
代替char buf[10]
避免char[]
安全問題, 才是C++
的正確開啟方式, 這下無論怎樣亂搞, 都不會有問題.
int data = 1234;
cout<<hex<<data<<endl;
cout<<oct<<data<<endl;
cout<<dec<<data<<endl;
複製程式碼
接下來, 我們來看看, C++
的進位制轉換, 使用<<hex
,代表16進位制, <<oct
, 代表8進位制, <<dec
,代表10進位制.
4d2
2322
1234
Program ended with exit code: 0
複製程式碼
使用<<hex
切換進位制, 注意雖然預設是10進位制但切換其他進位制後, 預設為切換後的進位制.
int data = 1234;
cout<<data<<endl;
cout<<setw(10)<<setiosflags(ios::left)<<data<<endl;
cout<<setw(10)<<setiosflags(ios::right)<<data<<endl;
複製程式碼
使用setw
和setiosflags
來設定域寬和左右對齊.
#include <iomanip>
複製程式碼
在使用setw
和setiosflags
之前需要新增標頭檔案.
1234
1234
1234
Program ended with exit code: 0
複製程式碼
以上就是使用setw
和setiosflags
的列印結果.
int a = 12;
int b = 3;
int c = 5;
cout<<setfill(`0`)<<setw(2)<<a<<":"<<setw(2)<<b<<":"<<setw(2)<<c<<endl;
複製程式碼
使用setfill
進行填充, 這個就不多說了, 試試就知道.
float f = 1.23456;
cout<<f<<endl;
cout<<setprecision(4)<<f<<endl;
cout<<setprecision(4)<<setiosflags(ios::fixed)<<f<<endl;
複製程式碼
使用setprecision
來調整浮點數的精度.
函式過載
函式過載, 會出現重名的函式, 重名的函式會根據語境來決定呼叫, 運算子過載也是一種函式過載.
void func(int a) {
cout<<"void func(int a)"<<endl;
}
void func(float a) {
cout<<"void func(float a)"<<endl;
}
void func(char a) {
cout<<"void func(char a)"<<endl;
}
int main(int argc, const char * argv[]) {
int a = 1;
func(a);
float b = 1.2;
func(b);
char c = `c`;
func(c);
return 0;
}
複製程式碼
void func(int a)
void func(float a)
void func(char a)
複製程式碼
函式過載是一種簡潔的需要, 函式返回值型別不能構成函式過載的標誌.
過載底層實現使用命名傾軋來改變函式名, 區分不同引數不同的同名函式.
#ifndef mystr_h
#define mystr_h
#include <stdio.h>
extern "C" int myStrlen(const char *s);
#endif /* mystr_h */
#include "mystr.h"
//extern "C" {
int myStrlen(const char *s) {
int len = 0;
while (*s) {
len++;
s++;
}
return len;
}
//}
複製程式碼
C++
預設進行傾軋, 使用extern "C"
來避免傾軋造成的連結錯誤. 用來連線C
的庫.
運算子過載
和上面講的相同, 運算子過載的本質其實也是一種函式過載, 相信熟悉Swift
的你, 一定不會陌生.
typedef struct _pos {
int x_;
int y_;
} Pos;
bool operator== (Pos one, Pos another) {
if (one.x_ == another.x_ && one.y_ == another.y_) {
return true;
} else {
return false;
}
}
int main(int argc, const char * argv[]) {
Pos ps = {1, 2};
Pos fdPs = {3, 4};
if (ps == fdPs) {
cout<<"=="<<endl;
} else {
cout<<"!="<<endl;
}
return 0;
}
複製程式碼
Pos ps = {1, 2};
Pos fdPs = {3, 4};
if (operator==(ps, fdPs)) {
cout<<"=="<<endl;
} else {
cout<<"!="<<endl;
}
複製程式碼
運算子過載其實也就是函式呼叫.
預設引數
OC
沒有預設引數, 而C++
卻有…., Swift
也有這個特性.
void foo(int a = 1, int b = 2, int c = 3) {
cout<<"====="<<endl;
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
int main(int argc, const char * argv[]) {
foo();
foo(2);
foo(2, 3);
foo(2, 3, 4);
return 0;
}
複製程式碼
=====
a = 1
b = 2
c = 3
=====
a = 2
b = 2
c = 3
=====
a = 2
b = 3
c = 3
=====
a = 2
b = 3
c = 4
複製程式碼
預設引數和函式過載可能會產生衝突. 優先選擇預設引數的方案.
引用
引用的本質是對指標的包裝, 避免使用裸露的指標, 引用是一種宣告關係, 不開闢空間, 這裡說不開闢, 只是程式碼層面看, 實際開始會開闢空間的.
int a = 100;
int &ra = a;
cout<<"a = "<<a<<endl;
cout<<"ra = "<<ra<<endl;
cout<<"&a = "<<&a<<endl;
cout<<"&ra = "<<&ra<<endl;
複製程式碼
a = 100
ra = 100
&a = 0x7ffeefbff5cc
&ra = 0x7ffeefbff5cc
Program ended with exit code: 0
複製程式碼
void swap(int &ra, int &rb) {
ra ^= rb;
rb ^= ra;
ra ^= rb;
}
int main(int argc, const char * argv[]) {
int a = 10;
int b = 20;
swap(a, b);
cout<<a<<"-"<<b<<endl;
return 0;
}
複製程式碼
20-10
複製程式碼
傳引用等於傳作用域, 這一點熟悉OC
的同學其實根本不用在意.
void swap(char **a, char **b) {
char *t = *a;
*a = *b;
*b = t;
}
void swap(char * &ra, char * &rb) {
char *t = ra;
ra = rb;
rb = t;
}
int main(int argc, const char * argv[]) {
char *p = "china";
char *q = "canada";
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
swap(&p, &q);
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
swap(p, q);
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
return 0;
}
複製程式碼
p = china
q = canada
p = canada
q = china
p = china
q = canada
複製程式碼
上面是指標的引用, 並沒有引用的指標.
int * p;
int ** pp = &p;
int *** ppp = &pp;
int **** pppp = &ppp;
int a;
int &ra = a;
int &rb = ra;
int &rc = rb;
複製程式碼
引用為平級, 沒有指標的指標這種概念.
int arr[10] = {1, 2, 3 ,4, 5, 6, 7};
int * const & parr = arr;
for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
cout<<parr[i]<<endl;
}
int (& rarr)[10] = arr;
cout<<"sizeof = "<<sizeof(rarr)<<endl;
return 0;
複製程式碼
上面是陣列的引用, 陣列的引用呢, 在OC
上就是*
, 而底層原來是這樣實現的.
int foo() {
int a = 200;
return a;
}
int main(int argc, const char * argv[]) {
const int & c = 100;
cout<<c<<endl;
int a = 3; int b = 5;
const int & ret = a + b;
cout<<ret<<endl;
const int & ra = foo();
cout<<ra<<endl;
double d = 100.12;
double & rd = d;
const int & rd2 = d;
cout<<rd<<endl;
cout<<rd2<<endl;
rd = 200.14;
cout<<rd<<endl;
cout<<rd2<<endl;
return 0;
}
複製程式碼
100
8
200
100.12
100
200.14
100
Program ended with exit code: 0
複製程式碼
常引用, 引用的是一個暫存器常量. 和巨集在預編譯期間替換不同, 常引用在彙編期間通過暫存器替換.
void foo(int & ri, char & rc) {
cout<<sizeof(ri)<<" "<<sizeof(rc)<<endl;
}
struct TypeC {
char c;
};
struct TypeP {
char * pc;
};
struct TypeR {
char & rc;
};
void mySwap(int * pa, int * pb) {
int t = *pa;
*pa = *pb;
*pb = t;
}
void mySwap(int & ra, int & rb) {
int t = ra;
ra = rb;
rb = t;
}
int main(int argc, const char * argv[]) {
int a; char c;
foo(a, c);
cout<<"sizeof(TypeC) = "<<sizeof(TypeC)<<endl;
cout<<"sizeof(TypeP) = "<<sizeof(TypeP)<<endl;
cout<<"sizeof(TypeR) = "<<sizeof(TypeR)<<endl;
int n = 3, m = 5;
mySwap(&n, &m);
cout<<n<<" "<<m<<endl;
mySwap(n, m);
cout<<n<<" "<<m<<endl;
return 0;
}
複製程式碼
我們等下用匯編來對比一下指標和引用之前的區別.
0x100001060 <+0>: pushq %rbp
0x100001061 <+1>: movq %rsp, %rbp
0x100001064 <+4>: movq %rdi, -0x8(%rbp)
0x100001068 <+8>: movq %rsi, -0x10(%rbp)
0x10000106c <+12>: movq -0x8(%rbp), %rsi
0x100001070 <+16>: movl (%rsi), %eax
0x100001072 <+18>: movl %eax, -0x14(%rbp)
0x100001075 <+21>: movq -0x10(%rbp), %rsi
0x100001079 <+25>: movl (%rsi), %eax
0x10000107b <+27>: movq -0x8(%rbp), %rsi
0x10000107f <+31>: movl %eax, (%rsi)
-> 0x100001081 <+33>: movl -0x14(%rbp), %eax
0x100001084 <+36>: movq -0x10(%rbp), %rsi
0x100001088 <+40>: movl %eax, (%rsi)
0x10000108a <+42>: popq %rbp
0x10000108b <+43>: retq
複製程式碼
指標的彙編
0x100001090 <+0>: pushq %rbp
0x100001091 <+1>: movq %rsp, %rbp
0x100001094 <+4>: movq %rdi, -0x8(%rbp)
0x100001098 <+8>: movq %rsi, -0x10(%rbp)
0x10000109c <+12>: movq -0x8(%rbp), %rsi
0x1000010a0 <+16>: movl (%rsi), %eax
0x1000010a2 <+18>: movl %eax, -0x14(%rbp)
0x1000010a5 <+21>: movq -0x10(%rbp), %rsi
0x1000010a9 <+25>: movl (%rsi), %eax
0x1000010ab <+27>: movq -0x8(%rbp), %rsi
0x1000010af <+31>: movl %eax, (%rsi)
-> 0x1000010b1 <+33>: movl -0x14(%rbp), %eax
0x1000010b4 <+36>: movq -0x10(%rbp), %rsi
0x1000010b8 <+40>: movl %eax, (%rsi)
0x1000010ba <+42>: popq %rbp
0x1000010bb <+43>: retq
複製程式碼
引用的彙編
引用的本質是個指標, 必須初始化, 長指標, 一經宣告不可改變. 類似於 int * const p
.
new 和 delete
new
和delete
, 還有new[]
, delete[]
, 是用來代替malloc
和free
的, 兩者之間不能串用.
int * p1 = (int *)malloc(sizeof(int));
int * p2 = new int;
*p2 = 100;
cout<<*p1<<" "<<*p2<<endl;
int **pp1 = (int **)malloc(sizeof(int *));
int **pp2 = new int *;
pp1 = pp2;
struct Stu {
float score;
char name[30];
char sex;
};
Stu * ps1 = (Stu *)malloc(sizeof(Stu));
Stu * ps2 = new Stu;
cout<<sizeof(*ps1)<<" "<<sizeof(*ps2)<<endl;
複製程式碼
0 100
36 36
複製程式碼
以上是new
和 malloc
的比較.
float * pf1 = (float *)malloc(10 * sizeof(float));
float * pf2 = new float[10]{1.2, 3.4};
for (int i = 0; i < 10; i++) {
cout<<pf1[i]<<" "<<pf2[i]<<endl;
}
char ** pp = new char * [10];
for (int i = 0; i < 10; i++) {
pp[i] = "Castiel";
}
pp[10] = nullptr;
while (*pp) {
cout<<*pp++<<endl;
}
int (* p)[5] = new int[3][5];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
p[i][j] = i + j;
}
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
cout<<p[i][j]<<" ";
}
cout<<endl;
}
int (* p2)[3][5] = new int[2][3][5];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 5; k++) {
p2[i][j][k] = i + j + k;
}
}
}
複製程式碼
對於連續的空間, 也就是陣列來說, 我們可以使用new[]
, 來開闢堆記憶體.
0 1.2
0 3.4
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
Castiel
Castiel
Castiel
Castiel
Castiel
Castiel
Castiel
Castiel
Castiel
Castiel
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
複製程式碼
上述程式碼的列印日誌.
int * p = new int;
delete p;
int ** pp = new int * [10];
delete []pp;
int (*ppp)[5] = new int[3][5];
delete []ppp;
複製程式碼
delete
與 delete[]
, 就是釋放記憶體和連續的記憶體.
char ** p = new char * [10];
for (int i = 0; i < 10; i++) {
p[i] = new char[10];
}
for (int i = 0; i < 10; i++) {
delete []p[i];
}
delete []p;
複製程式碼
釋放由內向外, 層級釋放.
try {
double * pd[50];
for (int i = 0; i< 50; i++) {
pd[i] = new double[500000000000];
cout<<i<<endl;
}
} catch (bad_alloc & e) {
cout<<"記憶體申請異常 "<<e.what()<<endl;
}
複製程式碼
... cpp
C++(37659,0x100395340) malloc: *** mach_vm_map(size=4000000000000) failed (error code=3)
*** error: can`t allocate region
*** set a breakpoint in malloc_error_break to debug
記憶體申請異常 std::bad_alloc
Program ended with exit code: 0
複製程式碼
對於堆記憶體申請失敗的異常捕獲的第一種方式, try-catch
, 貌似OC
中很少用到, 因為OC
可以給空物件傳送訊息.
void newError( ) {
cout<<"記憶體申請異常"<<endl;
exit(1);
}
int main(int argc, const char * argv[]) {
double * pd[50];
set_new_handler(newError);
for (int i = 0; i< 50; i++) {
pd[i] = new double[500000000000];
cout<<i<<endl;
}
return 0;
}
複製程式碼
...
C++(37705,0x100395340) malloc: *** mach_vm_map(size=4000000000000) failed (error code=3)
*** error: can`t allocate region
*** set a breakpoint in malloc_error_break to debug
記憶體申請異常
Program ended with exit code: 1
複製程式碼
第二種是使用set_new_handler
回撥函式來進行捕獲.
double * pd[50];
for (int i = 0; i< 50; i++) {
pd[i] = new (nothrow)double[500000000000];
if (pd[i] == nullptr) {
cout<<"記憶體申請異常 "<<" "<<__FILE__<<" "<<__func__<<" "<<__LINE__<<endl;
}
}
複製程式碼
...
C++(37787,0x100395340) malloc: *** mach_vm_map(size=4000000000000) failed (error code=3)
*** error: can`t allocate region
*** set a breakpoint in malloc_error_break to debug
記憶體申請異常 /Users/zhushuangquan/Desktop/C++/C++/main.cpp main 19
複製程式碼
第三種則是不進行異常捕獲…., 三種情況優先使用try-catch
.
inline 行內函數
inline int sqr(int x) {
return x * x;
}
int main(int argc, const char * argv[]) {
int i = 0;
while (i < 5) {
printf("%d
", sqr(i++));
}
return 0;
}
複製程式碼
代替巨集函式, 會在程式碼段出現多個副本, 但取決於編譯器優化, 適用函式體小並被頻繁呼叫,
強制型別轉換
儘量不要強轉, 強轉是設計不足導致的.
double d; int i;
d = static_cast<double>(i);
i = static_cast<int>(d);
d = static_cast<double>(10) / 3;
cout<<d<<endl;
void * p; int * q;
p = q;
q = static_cast<int *>(p);
複製程式碼
3.33333
Program ended with exit code: 0
複製程式碼
static_cast
隱式轉化
int * m; int n;
m = reinterpret_cast<int *>(n);
複製程式碼
reinterpret_cast
指標與數值之間進行轉換
void foo(const int & a) {
const_cast<int &>(a) = 200;
}
int main(int argc, const char * argv[]) {
int a;
const int & ra = a;
a = 100;
cout<<a<<endl;
const_cast<int &>(ra) = 300;
cout<<ra<<endl;
cout<<a<<endl;
const int * p = &a;
*const_cast<int *>(p) = 400;
cout<<*p<<endl;
foo(a);
cout<<a<<endl;
return 0;
}
複製程式碼
const_cast
只作用與指標和引用, 去const
化
const int a = 100;
const int & ra = a;
const_cast<int &>(ra) = 200;
cout<<a<<endl;
cout<<ra<<endl;
複製程式碼
100
200
複製程式碼
對於const
修飾的值, 是不能改變的,
名稱空間
對於OC
是用字首, 對於Java
是用包名, 對於Swift
也有和C++
一樣的名稱空間.
void foo() {
cout<<"foo"<<endl;
}
int mm = 100;
int main(int argc, const char * argv[]) {
std::cout<<::mm<<endl;
::foo();
return 0;
}
複製程式碼
::
全域性無名名稱空間.
namespace ONE {
int x = 4;
}
namespace ANOTHER {
int x = 14;
}
int main(int argc, const char * argv[]) {
{
int x = 250;
cout<<ONE::x<<endl;
cout<<ANOTHER::x<<endl;
cout<<x<<endl;
}
{
using ONE::x;
cout<<x<<endl;
}
{
using namespace ANOTHER;
cout<<x<<endl;
}
return 0;
}
複製程式碼
4
14
250
4
14
Program ended with exit code: 0
複製程式碼
名稱空間的使用, 名稱空間只能定義在全域性.
第一種推薦使用, 第二種少用, 第三種禁用.
namespace ONE {
int x = 4;
namespace ANOTHER {
int x = 14;
}
}
int main(int argc, const char * argv[]) {
cout<<ONE::ANOTHER::x<<endl;
return 0;
}
複製程式碼
14
Program ended with exit code: 0
複製程式碼
名稱空間的巢狀.
namespace ONE {
int a = 4;
}
namespace ONE {
int b = 14;
}
int main(int argc, const char * argv[]) {
using namespace ONE;
cout<<a<<" "<<b<<endl;
return 0;
}
複製程式碼
同名名稱空間自動合併.
string
字串是C++
比 C
高階的地方, 操作起來也比C
簡單太多, 也比OC
簡單太多, 問OC
為啥那麼麻煩.
int * pi = new int(10);
cout<<pi<<endl;
cout<<*pi<<endl;
string * p = new string("Castiel");
cout<<p<<endl;
cout<<*p<<endl;
char * q = "Castiel";
cout<<q<<endl;
cout<<*q<<endl;
複製程式碼
0x100506740
10
0x10050c710
Castiel
Castiel
C
Program ended with exit code: 0
複製程式碼
雖然string
是一種類, 但已經可以和int的地位相同了.
string s;
cout<<sizeof(string)<<endl;
cout<<sizeof(s)<<endl;
string s1("Castiel");
string s2 = "Castiel";
cout<<s1<<" "<<s2<<endl;
cin>>s;
cout<<s<<endl;
getline(cin, s); //解決了空格的問題
cout<<s<<endl;
string s3 = "Great Wall";
cout<<s3.size()<<endl;
string s4 = " in China";
cout<<(s3 += s4)<<endl;
string s5 = "Great Wall";
if (s3 == s5) {
cout<<"=="<<endl;
} else {
cout<<"!="<<endl;
}
string s6;
cout<<(s6 = s3)<<endl;
string s7 = to_string(1234);
cout<<s7<<endl;
string s8 = "123abc";
cout<<stoi(s8)<<endl;
複製程式碼
24
24
Castiel Castiel
10
Great Wall in China
!=
Great Wall in China
1234
123
Program ended with exit code: 0
複製程式碼
上述是string
的基本使用, 沒啥技術含量.
class
在C++
中, 結構體和類的本質沒有什麼具體的區別, 只是許可權訪問上有些許不同, 而不是像以前認為的類是引用傳遞, 而結構體是值傳遞, 傳地址, 不也是值麼, 只不過能取地址… 笑.
struct Date {
void init(int year = 1970, int month = 01, int day = 01) {
_year = year;
_month = month;
_day = day;
}
void printDate() {
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
複製程式碼
struct
預設全部是public
.
class Date {
int _year;
int _month;
int _day;
public:
void init(int year = 1970, int month = 01, int day = 01) {
_year = year;
_month = month;
_day = day;
}
void printDate() {
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
};
複製程式碼
class
預設全部是private
.
int main(int argc, const char * argv[]) {
Date * date = new Date;
date->init(1992, 06, 19);
date->printDate();
delete date;
Date * date2 = new Date;
date2->init(2012, 12, 21);
date2->printDate();
delete date2;
return 0;
}
複製程式碼
1992-6-19
2012-12-21
(lldb) p/x date
(Date *) $0 = 0x000000010050e9c0
(lldb) p/x date2
(Date *) $1 = 0x000000010050f2b0
(lldb)
Program ended with exit code: 0
複製程式碼
從列印上來說, 結構體和類是一樣的, 可以說類的本質就是結構體指標, 但其實類也可以不用指標引用, 就變成了值傳遞? 又笑.
class Date {
private:
int _year;
int _month;
int _day;
public:
Date(int year = 1970, int month = 01, int day = 01);
~Date();
void printDate();
};
Date::Date(int year, int month, int day)
:_year(year), _month(month), _day(day){}
Date::~Date() {
cout<<"delete: "<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
void Date::printDate() {
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
int main(int argc, const char * argv[]) {
Date * date = new Date(1992, 06, 19);
date->printDate();
delete date;
Date * date2 = new Date(2012, 12, 21);
date2->printDate();
delete date2;
return 0;
}
複製程式碼
1992-6-19
delete: 1992-6-19
2012-12-21
delete: 2012-12-21
Program ended with exit code: 0
複製程式碼
class
多檔案的基本用法, 構造器, 析構器, 引數列表什麼的就不多說了.
namespace xxx {
int a;
void log();
}
void xxx::log() {
a = 120;
cout<<a<<endl;
}
複製程式碼
其實類名本質就是一個名稱空間. 怎麼又是名稱空間了呢, 再笑….
最後
更多新鮮文章可以關注並Star
, 我們一起學習.
GitHub Repo:coderZsq.github.io
Follow: coderZsq · GitHub