-
a是int型變量a的地址
(char *)將int型指針(指向4個字節(jié))轉(zhuǎn)換成char型指針(指向一個字節(jié))
char *p聲明一個char型指針變回量,答接受轉(zhuǎn)換的地址。
#include <stdio.h>
int main()
{
? ?int i = 0x1122;
? ?char * p = (char *)&i;
? ?if (p[0] == 0x22 && p[1] == 0x11) {
? ? ? ?printf("Little Endian\n");
? ?}
? ?else if (p[0] == 0x11 && p[1] == 0x22) {
? ? ? ?printf("Big Endian\n");
? ?}
}查看全部 -
計算機硬件有兩種儲存數(shù)據(jù)的方式:大端字節(jié)序(big endian)和小端字節(jié)序(little endian)。
如果一個使用小端字節(jié)序的電腦上,這個整數(shù)的高字節(jié)就會存放在高地址上:
現(xiàn)在大部分的機器,都采用了小端字節(jié)序。但是在 IO 方面,則大部分使用大端字節(jié)序。例如,你要使用網(wǎng)絡(luò)發(fā)送一個 int 類型的變量,要先把 int 轉(zhuǎn)換成大端字節(jié)序,然后通過網(wǎng)絡(luò)發(fā)送。
大端字節(jié)序又被稱之為網(wǎng)絡(luò)細(xì)節(jié)序。
查看全部 -
^ 異或
若參加運算的兩個二進(jìn)制位值相同則為0,否則為1。
<< 左移
各位全部左移若干位,高位丟棄,低位補 0 。
>> 右移
各二進(jìn)位全部右移若干位,對無符號數(shù),高位補 0 ,有符號數(shù),各編譯器處理方法不一樣,有的補符號位,有的補 0 。
查看全部 -
你知道大端字節(jié)序和小端字節(jié)序嗎?
字節(jié)序,就是 大于一個字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序。
計算機硬件有兩種儲存數(shù)據(jù)的方式:大端字節(jié)序(big endian)和小端字節(jié)序(little endian)。
我們現(xiàn)在有一個整數(shù)是258。用16進(jìn)制表示是0x0102,然后我們把這個整數(shù)拆分成兩個字節(jié),第一個字節(jié)為 0000 0001,第二個字節(jié)為 0000 0010。
如果在一個使用大端字節(jié)序的電腦上,這個整數(shù)會被這樣存放:
如果一個使用小端字節(jié)序的電腦上,這個整數(shù)的高字節(jié)就會存放在高地址上:
現(xiàn)在大部分的機器,都采用了小端字節(jié)序。但是在 IO 方面,則大部分使用大端字節(jié)序。例如,你要使用網(wǎng)絡(luò)發(fā)送一個 int 類型的變量,要先把 int 轉(zhuǎn)換成大端字節(jié)序,然后通過網(wǎng)絡(luò)發(fā)送。
大端字節(jié)序又被稱之為網(wǎng)絡(luò)細(xì)節(jié)序。
查看全部 -
不一樣的const關(guān)鍵字
C++ 中的 const 千變?nèi)f化,之前我們已經(jīng)學(xué)過使用 const 來做一個常量。const 在 C++ 中整體表示的語意是“不變的”,但是 const 申明在不同位置,卻會有不一樣的效果。這一小節(jié),我們來集中學(xué)習(xí)一下 const。
const 修飾普通變量
例如:
const int a = 20;
則表示 a 是一個常量,你不可以在后續(xù)對其進(jìn)行修改。因為 a 不可修改,所以在創(chuàng)建的時候就要對 a 進(jìn)行賦值,不對其進(jìn)行賦值則會報錯。例如,下面的代碼就會報錯
const int a;
const 修飾指針
const 修飾指針可以分為多種情況:
只有一個 const,如果 const 位*左側(cè),表示指針?biāo)笖?shù)據(jù)是常量,不能通過解引用修改該數(shù)據(jù);指針本身是變量,可以指向其他的內(nèi)存單元
int aaa = 20; int bbb = 30; const int * constPoint = &aaa; constPoint = &bbb; *constPoint = 80; // 這行代碼會報錯
只有一個 const,如果 const 位于*右側(cè),表示指針本身是常量,不能指向其他內(nèi)存地址;指針?biāo)傅臄?shù)據(jù)可以通過解引用修改
int aaa = 20; int bbb = 30; int * const constPoint = &aaa; constPoint = &bbb; // 這行代碼會報錯 *constPoint = 80;
兩個 const,*左右各一個,表示指針和指針?biāo)笖?shù)據(jù)都不能修改
int aaa = 20; int bbb = 30; const int * const constPoint = &aaa; constPoint = &bbb; // 這行代碼會報錯 *constPoint = 80; // 這行代碼會報錯
const 修飾函數(shù)參數(shù)
const 修飾函數(shù)參數(shù)和修飾普通函數(shù)是一樣的。但是要注意的時候 const 修飾函數(shù)參數(shù)的時候,其作用域僅僅限制在函數(shù)內(nèi)部。也就是說,你可以把一個不用 const 修飾的參數(shù)傳入到 const 修飾的參數(shù)中去。而只要在函數(shù)中保持其不變性就可以了。
const 修飾成員函數(shù)
const 修飾的成員函數(shù)不能修改任何的成員變量
class A { public: ? ? int aaa; ? ? int funcA() const ? ? { ? ? ? ? aaa = 20; // 這行代碼會報錯 ? ? ? ? return 0; ? ? } }
const 成員函數(shù)不能調(diào)用非 const 成員函數(shù)
class A { public: ? ? int aaa; ? ? int funcA() const ? ? { ? ? ? ? funcB(); // 這行代碼會報錯 ? ? ? ? return 0; ? ? } ? ? int funcB() ? ? { ? ? ? ? return 0; ? ? } }
const 修飾函數(shù)返回值修飾返回值要分成兩種情況
址傳遞,返回指針,引用。
在 C++ 中有時我們會寫這樣的代碼:
A aaa; A & getA(){ ? ? return aaa; } int main(int argc,char **argv) { ? ? A bbb; ? ? getA() = bbb; ? ? return 0; }
上面的代碼運行之后,aaa 變量就會被 bbb 所賦值,但是有些時候這樣做會造成一些混亂
例如:
getA() == a
有時候會有筆誤:
getA() = a
這種情況下,就會有問題,而且不容易被找到這個錯誤。
所以在大多數(shù)情況下,我們可以給返回值加一個 const ,這樣可以防止返回值被調(diào)用。
A aaa; const A & getA(){ ? ? return aaa; } int main(int argc,char **argv) { ? ? A bbb; ? ? getA() = bbb; // 這行代碼會報錯 ? ? return 0; }
值傳遞。
值傳遞就簡單多了,因為值傳遞的時候,返回值會被復(fù)制一份,所以加不加 const 都可以。
查看全部 -
C++ 中的空指針
我們之前的課程中曾經(jīng)講過空指針的問題,知道在 C++ 中,有使用 NULL 和 nullptr 兩種方式表示空指針的方法。
int * p = NULL; int * p = nullptr;
這一小節(jié)來看看兩者的區(qū)別。
NULL
首先看 NULL,在 C++ 中,NULL 其實就是 0。
例如:
int * p = NULL;
等價于:
int * p = 0;
因為在 C++ 中,0 地址通常是被保護(hù)起來的,不可訪問的。因此用 0 地址來指代這個指針哪里都不指,是可以的。但是這里面卻存在一些問題。因為 NULL 就是 0,所以我們可以把 NULL 用在其他地方。
例如:
int a = NULL;
我們可以將一個 int 變量賦值成 NULL,你永遠(yuǎn)無法阻止有人這么干。而在某些情況下,甚至?xí)诓唤?jīng)意間釀成慘劇。
例如:
class A { public: ? ? void func(void * t) ? ? { ? ? } ? ? void func(int i) ? ? { ? ? } }
這個類中,func 函數(shù)有兩個重載。這個時候,我們嘗試用 NULL 調(diào)用一下:
int main(int argc,char **argv) { ? ? A a; ? ? a.func(NULL); ? ? return 0; }
猜猜這個函數(shù)到底調(diào)用的哪個重載?
nullptr
正是由于 NULL 會導(dǎo)致這樣的混亂,所以在 C++11 標(biāo)準(zhǔn)之后,C++ 標(biāo)準(zhǔn)委員會為 C++ 添加了 nullptr 關(guān)鍵字。我們可以將 NULL 賦值給一個普通變量,而 nullptr 卻不能。
int a = nullptr;
這樣是會直接報錯的。
nullptr 只能賦值給指針,所以不會有 NULL 那樣的問題。
所以,只要你的編譯器兼容 C++11 標(biāo)準(zhǔn),那么你應(yīng)該使用 nullptr。
查看全部 -
霸道總裁眼中的命令員工:父類和子類的相互轉(zhuǎn)換
我們在之前的課程中學(xué)習(xí)過數(shù)據(jù)類型之間的轉(zhuǎn)換,某些可以隱式轉(zhuǎn)換,某些需要顯式轉(zhuǎn)換。
例如,我們可以把 int 轉(zhuǎn)成 long long。
int a = 100; long long b = a;
由于是小類型轉(zhuǎn)大類型,所以這里使用隱式轉(zhuǎn)換就可以了。
再比如,我們可以把 long long 轉(zhuǎn)成 int。
long long a = 100; int b = (int)a;
這里是大類型轉(zhuǎn)小類型,所以要顯式轉(zhuǎn)換。這種轉(zhuǎn)換可能會損失精度,是需要我們程序員掌控的。
類的轉(zhuǎn)換
同樣,類之間也可以相互轉(zhuǎn)換。類的轉(zhuǎn)換主要是在父類和子類之間的轉(zhuǎn)換。
首先,我們先來看看父類和子類之間的邏輯關(guān)系
class Staff { public: ? ? std::string name; ? ? int age; } ?class Coder : public Staff { public: ? ? std::string language; };
這里有兩個類,一個類是 Staff 員工類,里面包括兩個屬性,name 和 age。Coder 程序員類繼承自員工類,所以其包含了 Staff 的屬性,除此之外,還有一個 language 屬性,表示其使用的編程語言。
我們其實可以把一個員工強行轉(zhuǎn)化成程序員,但是這就有可能出問題,就如同我們把 long long 轉(zhuǎn)成 int 就有可能出現(xiàn)問題。
int main(int argc,char **argv) { ? ? Coder * coder = new Coder(); ? ? Staff * staff = coder; // 隱式轉(zhuǎn)換就可以 ? ? Coder * coder = (Coder *)staff; // 必須顯式轉(zhuǎn)換 ? ? return 0; }
查看全部 -
動態(tài)編聯(lián)和靜態(tài)編聯(lián)
上一小節(jié),我們介紹了父類和子類的轉(zhuǎn)換,也簡單介紹了多態(tài),從這節(jié)開始,我們詳細(xì)介紹多態(tài)。
class Base { public: ? ? void func(){ ? ? ? ? printf("this is Base\n"); ? ? } } class Child : public Base { public: ? ? void func(){ ? ? ? ? printf("this is Child\n"); ? ? } } ?int main(int argc,char **argv) { ? ? Child * obj = new Child(); ? ? Base * baseobj = (Base *)obj; ? ? baseobj->func(); ? ? delete obj; ? ? return 0; }
我們之前講述了什么是多態(tài),還用了一個例子,將一個指針的類型做成強轉(zhuǎn),然后調(diào)用 func 函數(shù),就會發(fā)現(xiàn), func 函數(shù)會隨著被強轉(zhuǎn)的類型的變換而變換,這種函數(shù)的關(guān)聯(lián)過程稱為編聯(lián)。按照聯(lián)編所進(jìn)行的階段不同,可分為兩種不同的聯(lián)編方法:靜態(tài)聯(lián)編和動態(tài)聯(lián)編。
靜態(tài)編聯(lián)
Child * obj = new Child(); Base * baseobj = (Base *)obj; baseobj->func(); delete obj; return 0;
再來看看這個例子,我們通過強制轉(zhuǎn)換來指定 func 執(zhí)行的是哪個。這個過程是在編譯階段就將函數(shù)實現(xiàn)和函數(shù)調(diào)用關(guān)聯(lián)起來,因此靜態(tài)聯(lián)編也叫早綁定,在編譯階段就必須了解所有的函數(shù)或模塊執(zhí)行所需要檢測的信息。
動態(tài)編聯(lián)
除了靜態(tài)編聯(lián)之外,C++ 還支持動態(tài)編聯(lián)。動態(tài)聯(lián)編是指聯(lián)編在程序運行時動態(tài)地進(jìn)行,根據(jù)當(dāng)時的情況來確定調(diào)用哪個同名函數(shù),實際上是在運行時虛函數(shù)的實現(xiàn)。當(dāng)然,我們現(xiàn)在所學(xué)的知識還沒辦法完成動態(tài)編聯(lián),接下來,我們將要學(xué)習(xí)虛函數(shù),來實現(xiàn)動態(tài)編聯(lián)。
查看全部 -
引用和指針用法的區(qū)別。
查看全部 -
引用和指針功能一樣,引用必須要初始化,賦值nullptr。
int &ra = a;
引用只能指向一個地址,而指針可以變化自己的指向地址。
查看全部 -
純虛函數(shù)只可以被繼承。
將父類的析構(gòu)函數(shù)聲明為虛函數(shù),作用是用父類的指針刪除一個派生類對象時,派生類對象的析構(gòu)函數(shù)會被調(diào)用。例如:
class Staff
{
public:
? ?std::string name;
? ?int age;
? ?virtual ~Staff()
? ?{
? ?}
}
class Coder : public Staff
{
public:
? ?std::string language;
? ?virtual ~Coder()
? ?{
? ?}
};
int main(int argc,char **argv)
{
? ?Staff * s = new Coder();
? ?delete s;
? ?return 0;
}此時如果析構(gòu)函數(shù)不加 virtual,那么 delete 父類指針的時候,子類的析構(gòu)就不會被調(diào)用,某些情況下會導(dǎo)致內(nèi)存泄漏。
查看全部 -
純虛函數(shù)只可以被繼承。
將父類的析構(gòu)函數(shù)聲明為虛函數(shù),作用是用父類的指針刪除一個派生類對象時,派生類對象的析構(gòu)函數(shù)會被調(diào)用。例如:
class Staff
{
public:
? ?std::string name;
? ?int age;
? ?virtual ~Staff()
? ?{
? ?}
}
class Coder : public Staff
{
public:
? ?std::string language;
? ?virtual ~Coder()
? ?{
? ?}
};
int main(int argc,char **argv)
{
? ?Staff * s = new Coder();
? ?delete s;
? ?return 0;
}此時如果析構(gòu)函數(shù)不加 virtual,那么 delete 父類指針的時候,子類的析構(gòu)就不會被調(diào)用,某些情況下會導(dǎo)致內(nèi)存泄漏。
查看全部 -
給員工分部門:類的繼承
類,就像是對某一類事物的抽象模版,我們可以根據(jù)這個模版生產(chǎn)出具有相同屬性的對象。例如,我們之前將員工抽象成了 Staff 類。
而在某些場景下,我們希望對抽象的內(nèi)容進(jìn)行擴增,或者說更加具體化。例如,我們之前定義了員工,但是員工只是很抽象的一個概念,員工和員工是不一樣的,例如,程序員和會計都是員工,他們都具有員工應(yīng)有的屬性,但是除此之外,他們還有額外屬于自己的東西。
為了完成這種關(guān)系,我們來學(xué)習(xí)一下繼承。
例如,我們可以來寫一個程序員類,名字叫做 Coder
class Coder { };
這個 Coder 是員工的一種,他具有員工的所有屬性,所以,我們可以讓 Coder 繼承自 Staff
class Coder : public Staff { };
當(dāng)然,除了具有 Staff 的所有內(nèi)容之外,Coder 還有屬于自己的動作,那就是寫代碼,我們就可以這樣寫:
class Coder : public Staff { public: ? ? void code() ? ? { ? ? ? ? printf("Coding!!!\n"); ? ? } };
這樣,Coder 這個類,除了具有 Staff 的所有成員變量和成員函數(shù)之外,還有了一個屬于自己的函數(shù)。
查看全部 -
面向過程的結(jié)構(gòu)化編程:把數(shù)據(jù)放入到動作當(dāng)中。采用自頂向下的方法構(gòu)建程序,包含順序,選擇和循環(huán)三種結(jié)構(gòu)。按照程序執(zhí)行的時序步驟來完成。
類由成員函數(shù)和成員變量組成,可以通過實例化,得出很多的對象。
查看全部 -
運算符重載
RMB.h
class RMB { public: ? ? RMB(int _yuan, int _jiao, int _fen); ? ? ~RMB(); private: ? ? int yuan = 0; ? ? int jiao = 0; ? ? int fen = 0; };
RMB.cpp
#include "RMB.h" RMB::RMB(int _yuan, int _jiao, int _fen) { ? ? yuan = _yuan; ? ? jiao = _jiao; ? ? fen = _fen; } RMB::~RMB() { }
為這個類寫了些必要的部分之后,我們要完成一個功能,加法功能,1塊9毛加2塊3毛,用程序應(yīng)該怎么寫呢?我們可以添加一個 Add 函數(shù),如下:
RMB.h
class RMB { public: ? ? RMB(int _yuan, int _jiao, int _fen); ? ? ~RMB(); ? ? RMB Add(const RMB & rmb); private: ? ? int yuan = 0; ? ? int jiao = 0; ? ? int fen = 0; };
RMB.cpp
#include "RMB.h" RMB::RMB(int _yuan, int _jiao, int _fen) { ? ? yuan = _yuan; ? ? jiao = _jiao; ? ? fen = _fen; } RMB::~RMB() { } RMB RMB::Add(const RMB & rmb) { ? ? RMB rmbRes(0, 0, 0); ? ? // 分 ? ? int f = rmb.fen + fen; ? ? int f_ = f / 10; ? ? rmbRes.fen = f % 10; ? ? // 角 ? ? int j = rmb.jiao + jiao + f_; ? ? int j_ = j / 10; ? ? rmbRes.jiao = j % 10; ? ? // 元 ? ? int y = rmb.yuan + yuan + j_; ? ? int y_ = y / 10; ? ? rmbRes.yuan = y % 10; ? ? return rmbRes; }
這樣,我們就實現(xiàn)了一個 Add 函數(shù),如果想要把兩個人民幣加起來,就可以這樣用:
int main(int argc,char **argv) { ? ? RMB rmbA(1, 9, 0); ? ? RMB rmbB(2, 5, 0); ? ? RMB rmbC = rmbA.Add(rmbB); ? ? return 0; }
但是這樣看上去好像有點別扭,事實上,在很多不支持運算符重載的語言里,我們都是這樣干的。但是在 C++ 里,有一種更好的方式,可以把 + 號進(jìn)行重載。
我們可以把這個 Add 函數(shù)修改成 + 號的重載:
RMB.h
class RMB { public: ? ? RMB(int _yuan, int _jiao, int _fen); ? ? ~RMB(); ? ? // RMB & Add(const RMB & rmb); ? ? RMB operator + (const RMB & rmb); private: ? ? int yuan = 0; ? ? int jiao = 0; ? ? int fen = 0; };
RMB.cpp
#include "RMB.h" RMB::RMB(int _yuan, int _jiao, int _fen) { ? ? yuan = _yuan; ? ? jiao = _jiao; ? ? fen = _fen; } RMB::~RMB() { } // RMB & RMB::Add(const RMB & rmb) RMB RMB::operator + (const RMB & rmb) { ? ? RMB rmbRes(0, 0, 0); ? ? // 分 ? ? int f = rmb.fen + fen; ? ? int f_ = f / 10; ? ? rmbRes.fen = f % 10; ? ? // 角 ? ? int j = rmb.jiao + jiao + f_; ? ? int j_ = j / 10; ? ? rmbRes.jiao = j % 10; ? ? // 元 ? ? int y = rmb.yuan + yuan + j_; ? ? int y_ = y / 10; ? ? rmbRes.yuan = y % 10; ? ? return rmbRes; }
在這樣修改之后,使用的時候,我們就可以寫出來更優(yōu)雅的代碼了。
int main(int argc,char **argv) { ? ? RMB rmbA(1, 9, 0); ? ? RMB rmbB(2, 5, 0); ? ? RMB rmbC = rmbA + rmbB; ? ? return 0; }
可以看到我們直接把兩個對象用 + 號加了起來,這比之前使用函數(shù)看起來會好得多。
在 C++ 中,有很多符號都可以重載,也有一些不能被重載。
查看全部 -
類
類,是 C++ 實現(xiàn)面向?qū)ο笞罨A(chǔ)的部分。類其實和之前學(xué)過的結(jié)構(gòu)體十分相似,你可以認(rèn)為類是結(jié)構(gòu)體的升級版。
類的申明
在 C++ 中,可以用下面的代碼申明一個員工類:
class Staff { };
可以像使用結(jié)構(gòu)體一樣使用這個類:
#include <stdio.h> class Staff { }; int main(int argc,char **argv) {? ? ?Staff st;? ? ?return 0; }
分文件編程
我們在此之前都是把代碼放到一個文件里,但是這樣在實際工程中肯定是不行的,我們不可能把所有的代碼都寫到一個文件夾里面。而在 C++ 中我們就常常把類定義到不同的文件里面,把每個類都獨立起來,這樣代碼的耦合性就會降低,方便維護(hù)。
在 C++ 中,我們可以把一個類寫到兩個文件里面,一個是后綴為 .h 或者 .hpp 的頭文件,一個是后綴為 .cpp 的實現(xiàn)文件。我們先在開發(fā)環(huán)境里新建一個類。輸入類名是 Staff。
可以看到 VS 為我們創(chuàng)建類兩個文件,Staff.h 和 Staff.cpp。Staff.h 文件為定義,Staff.cpp 為實現(xiàn)。
在分了文件之后,我們想要在 main 函數(shù)中引用這個類,就需要使用 #include “Staff.h” 將頭文件引入進(jìn)來。
實例化
在新建了一個類之后,我們就可以根據(jù)這個類產(chǎn)生對象了。根據(jù)類產(chǎn)生對象的過程叫做實例化。
#include "Staff.h"?
int main(int argc,char **argv)?
{? ? ?// 我們就這樣實例化了三個員工? ? ?
Staff st1;? ? ?
Staff st2;? ? ?
Staff st3;? ??
return 0;?
}
這樣分配,我們將這三個“員工”分配到了棧上,同樣的,可以把他們分配到堆內(nèi)存上面去。
new delete
要將對象分配到堆上,需要用到另外兩個關(guān)鍵字,new 和 delete。new 用來分配對象,delete 用來刪除對象。new 會返回一個指針,在使用完畢后,要通過 delete 把這個指針指向的地址釋放掉。
#include "Staff.h"?
int main(int argc,char **argv) {? ??
Staff * st1 = new Staff();? ? ?
Staff * st2 = new Staff();? ? ?
Staff * st3 = new Staff();? ? ?
// 記得釋放? ??
?delete st1;? ? ?
delete st2;? ? ?
delete st3;? ? ?
return 0;
?}
查看全部 -
霸道總裁的員工:類
我們上一小節(jié)中介紹了面向?qū)ο蟮乃枷?,這一小節(jié)開始,我們來具體看看在 C++ 中應(yīng)該如何實現(xiàn)面向?qū)ο蟆?/p>
類
類,是 C++ 實現(xiàn)面向?qū)ο笞罨A(chǔ)的部分。類其實和之前學(xué)過的結(jié)構(gòu)體十分相似,你可以認(rèn)為類是結(jié)構(gòu)體的升級版。
類的申明
在 C++ 中,可以用下面的代碼申明一個員工類:
class Staff { };
可以像使用結(jié)構(gòu)體一樣使用這個類:
#include <stdio.h> class Staff { }; int main(int argc,char **argv) {? ? ?Staff st;? ? ?return 0; }
分文件編程
我們在此之前都是把代碼放到一個文件里,但是這樣在實際工程中肯定是不行的,我們不可能把所有的代碼都寫到一個文件夾里面。而在 C++ 中我們就常常把類定義到不同的文件里面,把每個類都獨立起來,這樣代碼的耦合性就會降低,方便維護(hù)。
在 C++ 中,我們可以把一個類寫到兩個文件里面,一個是后綴為 .h 或者 .hpp 的頭文件,一個是后綴為 .cpp 的實現(xiàn)文件。我們先在開發(fā)環(huán)境里新建一個類。輸入類名是 Staff。
可以看到 VS 為我們創(chuàng)建類兩個文件,Staff.h 和 Staff.cpp。Staff.h 文件為定義,Staff.cpp 為實現(xiàn)。
在分了文件之后,我們想要在 main 函數(shù)中引用這個類,就需要使用 #include “Staff.h” 將頭文件引入進(jìn)來。
實例化
在新建了一個類之后,我們就可以根據(jù)這個類產(chǎn)生對象了。根據(jù)類產(chǎn)生對象的過程叫做實例化。
#include "Staff.h"?
int main(int argc,char **argv)?
{? ? ?// 我們就這樣實例化了三個員工? ? ?
Staff st1;? ? ?
Staff st2;? ? ?
Staff st3;? ??
return 0;?
? ??
}
這樣分配,我們將這三個“員工”分配到了棧上,同樣的,可以把他們分配到堆內(nèi)存上面去。
new delete
要將對象分配到堆上,需要用到另外兩個關(guān)鍵字,new 和 delete。new 用來分配對象,delete 用來刪除對象。new 會返回一個指針,在使用完畢后,要通過 delete 把這個指針指向的地址釋放掉。
#include "Staff.h"?
int main(int argc,char **argv) {? ??
Staff * st1 = new Staff();? ? ?
Staff * st2 = new Staff();? ? ?
Staff * st3 = new Staff();? ? ?
// 記得釋放? ??
?delete st1;? ? ?
delete st2;? ? ?
delete st3;? ? ?
return 0;
?}
查看全部 -
霸道總裁的員工:類
我們上一小節(jié)中介紹了面向?qū)ο蟮乃枷?,這一小節(jié)開始,我們來具體看看在 C++ 中應(yīng)該如何實現(xiàn)面向?qū)ο蟆?/p>
類
類,是 C++ 實現(xiàn)面向?qū)ο笞罨A(chǔ)的部分。類其實和之前學(xué)過的結(jié)構(gòu)體十分相似,你可以認(rèn)為類是結(jié)構(gòu)體的升級版。
類的申明
在 C++ 中,可以用下面的代碼申明一個員工類:
class Staff { };
可以像使用結(jié)構(gòu)體一樣使用這個類:
#include <stdio.h> class Staff { }; int main(int argc,char **argv) { ? ? Staff st; ? ? return 0; }
分文件編程
我們在此之前都是把代碼放到一個文件里,但是這樣在實際工程中肯定是不行的,我們不可能把所有的代碼都寫到一個文件夾里面。而在 C++ 中我們就常常把類定義到不同的文件里面,把每個類都獨立起來,這樣代碼的耦合性就會降低,方便維護(hù)。
在 C++ 中,我們可以把一個類寫到兩個文件里面,一個是后綴為 .h 或者 .hpp 的頭文件,一個是后綴為 .cpp 的實現(xiàn)文件。我們先在開發(fā)環(huán)境里新建一個類。輸入類名是 Staff。
可以看到 VS 為我們創(chuàng)建類兩個文件,Staff.h 和 Staff.cpp。Staff.h 文件為定義,Staff.cpp 為實現(xiàn)。
在分了文件之后,我們想要在 main 函數(shù)中引用這個類,就需要使用 #include “Staff.h” 將頭文件引入進(jìn)來。
實例化
在新建了一個類之后,我們就可以根據(jù)這個類產(chǎn)生對象了。根據(jù)類產(chǎn)生對象的過程叫做實例化。
#include "Staff.h" int main(int argc,char **argv) { ? ? // 我們就這樣實例化了三個員工 ? ? Staff st1; ? ? Staff st2; ? ? Staff st3; ? ? return 0; }
這樣分配,我們將這三個“員工”分配到了棧上,同樣的,可以把他們分配到堆內(nèi)存上面去。
new delete
要將對象分配到堆上,需要用到另外兩個關(guān)鍵字,new 和 delete。new 用來分配對象,delete 用來刪除對象。new 會返回一個指針,在使用完畢后,要通過 delete 把這個指針指向的地址釋放掉。
#include "Staff.h"?
int main(int argc,char **argv) {? ??
Staff * st1 = new Staff(); ? ??
Staff * st2 = new Staff(); ? ??
Staff * st3 = new Staff(); ? ??
// 記得釋放 ? ?
?delete st1; ? ??
delete st2; ? ??
delete st3; ? ??
return 0;
?}
查看全部 -
霸道總裁的員工:類
我們上一小節(jié)中介紹了面向?qū)ο蟮乃枷?,這一小節(jié)開始,我們來具體看看在 C++ 中應(yīng)該如何實現(xiàn)面向?qū)ο蟆?/p>
類
類,是 C++ 實現(xiàn)面向?qū)ο笞罨A(chǔ)的部分。類其實和之前學(xué)過的結(jié)構(gòu)體十分相似,你可以認(rèn)為類是結(jié)構(gòu)體的升級版。
類的申明
在 C++ 中,可以用下面的代碼申明一個員工類:
class Staff { };
可以像使用結(jié)構(gòu)體一樣使用這個類:
#include <stdio.h> class Staff { }; int main(int argc,char **argv) { ? ? Staff st; ? ? return 0; }
分文件編程
我們在此之前都是把代碼放到一個文件里,但是這樣在實際工程中肯定是不行的,我們不可能把所有的代碼都寫到一個文件夾里面。而在 C++ 中我們就常常把類定義到不同的文件里面,把每個類都獨立起來,這樣代碼的耦合性就會降低,方便維護(hù)。
在 C++ 中,我們可以把一個類寫到兩個文件里面,一個是后綴為 .h 或者 .hpp 的頭文件,一個是后綴為 .cpp 的實現(xiàn)文件。我們先在開發(fā)環(huán)境里新建一個類。輸入類名是 Staff。
可以看到 VS 為我們創(chuàng)建類兩個文件,Staff.h 和 Staff.cpp。Staff.h 文件為定義,Staff.cpp 為實現(xiàn)。
在分了文件之后,我們想要在 main 函數(shù)中引用這個類,就需要使用 #include “Staff.h” 將頭文件引入進(jìn)來。
實例化
在新建了一個類之后,我們就可以根據(jù)這個類產(chǎn)生對象了。根據(jù)類產(chǎn)生對象的過程叫做實例化。這個過程就像是公司招聘員工一樣,幸運的是,我們作為程序的老板,并不需要和現(xiàn)實中一樣去張貼招聘啟示。在 C++ 中,“招聘“員工,只需要用以下的代碼就可以了。
#include "Staff.h" int main(int argc,char **argv) { ? ? // 我們就這樣實例化了三個員工 ? ? Staff st1; ? ? Staff st2; ? ? Staff st3; ? ? return 0; }
這樣分配,我們將這三個“員工”分配到了棧上,同樣的,可以把他們分配到堆內(nèi)存上面去。
new delete
要將對象分配到堆上,需要用到另外兩個關(guān)鍵字,new 和 delete。new 用來分配對象,delete 用來刪除對象。new 會返回一個指針,在使用完畢后,要通過 delete 把這個指針指向的地址釋放掉。
#include "Staff.h" int main(int argc,char **argv) { ? ? // 我們就這樣實例化了三個員工 ? ? Staff * st1 = new Staff(); ? ? Staff * st2 = new Staff(); ? ? Staff * st3 = new Staff(); ? ? // 記得釋放 ? ? delete st1; ? ? delete st2; ? ? delete st3; ? ? return 0; }
查看全部 -
霸道總裁的員工:類
我們上一小節(jié)中介紹了面向?qū)ο蟮乃枷耄@一小節(jié)開始,我們來具體看看在 C++ 中應(yīng)該如何實現(xiàn)面向?qū)ο蟆?/p>
類
類,是 C++ 實現(xiàn)面向?qū)ο笞罨A(chǔ)的部分。類其實和之前學(xué)過的結(jié)構(gòu)體十分相似,你可以認(rèn)為類是結(jié)構(gòu)體的升級版。之后的學(xué)習(xí)中你會更加理解類?,F(xiàn)在,我們只簡單得來介紹一下類。
類的申明
在 C++ 中,可以用下面的代碼申明一個員工類:
class Staff { };
可以像使用結(jié)構(gòu)體一樣使用這個類:
#include <stdio.h> class Staff { }; int main(int argc,char **argv) { ? ? Staff st; ? ? return 0; }
分文件編程
我們在此之前都是把代碼放到一個文件里,但是這樣在實際工程中肯定是不行的,我們不可能把所有的代碼都寫到一個文件夾里面。而在 C++ 中我們就常常把類定義到不同的文件里面,把每個類都獨立起來,這樣代碼的耦合性就會降低,方便維護(hù)。
在 C++ 中,我們可以把一個類寫到兩個文件里面,一個是后綴為 .h 或者 .hpp 的頭文件,一個是后綴為 .cpp 的實現(xiàn)文件。我們先在開發(fā)環(huán)境里新建一個類。輸入類名是 Staff。
可以看到 VS 為我們創(chuàng)建類兩個文件,Staff.h 和 Staff.cpp。Staff.h 文件為定義,Staff.cpp 為實現(xiàn)。
在分了文件之后,我們想要在 main 函數(shù)中引用這個類,就需要使用 #include “Staff.h” 將頭文件引入進(jìn)來。
實例化
在新建了一個類之后,我們就可以根據(jù)這個類產(chǎn)生對象了。根據(jù)類產(chǎn)生對象的過程叫做實例化。這個過程就像是公司招聘員工一樣,幸運的是,我們作為程序的老板,并不需要和現(xiàn)實中一樣去張貼招聘啟示。在 C++ 中,“招聘“員工,只需要用以下的代碼就可以了。
#include "Staff.h" int main(int argc,char **argv) { ? ? // 我們就這樣實例化了三個員工 ? ? Staff st1; ? ? Staff st2; ? ? Staff st3; ? ? return 0; }
這樣分配,我們將這三個“員工”分配到了棧上,同樣的,可以把他們分配到堆內(nèi)存上面去。
new delete
要將對象分配到堆上,需要用到另外兩個關(guān)鍵字,new 和 delete。new 用來分配對象,delete 用來刪除對象。new 會返回一個指針,在使用完畢后,要通過 delete 把這個指針指向的地址釋放掉。
#include "Staff.h" int main(int argc,char **argv) { ? ? // 我們就這樣實例化了三個員工 ? ? Staff * st1 = new Staff(); ? ? Staff * st2 = new Staff(); ? ? Staff * st3 = new Staff(); ? ? // 記得釋放 ? ? delete st1; ? ? delete st2; ? ? delete st3; ? ? return 0; }
查看全部 -
霸道總裁的員工:類
我們上一小節(jié)中介紹了面向?qū)ο蟮乃枷?,這一小節(jié)開始,我們來具體看看在 C++ 中應(yīng)該如何實現(xiàn)面向?qū)ο蟆?/p>
類
類,是 C++ 實現(xiàn)面向?qū)ο笞罨A(chǔ)的部分。類其實和之前學(xué)過的結(jié)構(gòu)體十分相似,你可以認(rèn)為類是結(jié)構(gòu)體的升級版。之后的學(xué)習(xí)中你會更加理解類。現(xiàn)在,我們只簡單得來介紹一下類。
類的申明
在 C++ 中,可以用下面的代碼申明一個員工類:
class Staff { };
可以像使用結(jié)構(gòu)體一樣使用這個類:
#include <stdio.h> class Staff { }; int main(int argc,char **argv) { ? ? Staff st; ? ? return 0; }
分文件編程
我們在此之前都是把代碼放到一個文件里,但是這樣在實際工程中肯定是不行的,我們不可能把所有的代碼都寫到一個文件夾里面。而在 C++ 中我們就常常把類定義到不同的文件里面,把每個類都獨立起來,這樣代碼的耦合性就會降低,方便維護(hù)。
在 C++ 中,我們可以把一個類寫到兩個文件里面,一個是后綴為 .h 或者 .hpp 的頭文件,一個是后綴為 .cpp 的實現(xiàn)文件。我們先在開發(fā)環(huán)境里新建一個類。輸入類名是 Staff。
可以看到 VS 為我們創(chuàng)建類兩個文件,Staff.h 和 Staff.cpp。Staff.h 文件為定義,Staff.cpp 為實現(xiàn)。
在分了文件之后,我們想要在 main 函數(shù)中引用這個類,就需要使用 #include “Staff.h” 將頭文件引入進(jìn)來。
實例化
在新建了一個類之后,我們就可以根據(jù)這個類產(chǎn)生對象了。根據(jù)類產(chǎn)生對象的過程叫做實例化。這個過程就像是公司招聘員工一樣,幸運的是,我們作為程序的老板,并不需要和現(xiàn)實中一樣去張貼招聘啟示。在 C++ 中,“招聘“員工,只需要用以下的代碼就可以了。
#include "Staff.h" int main(int argc,char **argv) { ? ? // 我們就這樣實例化了三個員工 ? ? Staff st1; ? ? Staff st2; ? ? Staff st3; ? ? return 0; }
這樣分配,我們將這三個“員工”分配到了棧上,同樣的,可以把他們分配到堆內(nèi)存上面去。
new delete
要將對象分配到堆上,需要用到另外兩個關(guān)鍵字,new 和 delete。new 用來分配對象,delete 用來刪除對象。new 會返回一個指針,在使用完畢后,要通過 delete 把這個指針指向的地址釋放掉。
#include "Staff.h" int main(int argc,char **argv) { ? ? // 我們就這樣實例化了三個員工 ? ? Staff * st1 = new Staff(); ? ? Staff * st2 = new Staff(); ? ? Staff * st3 = new Staff(); ? ? // 記得釋放 ? ? delete st1; ? ? delete st2; ? ? delete st3; ? ? return 0; }
查看全部 -
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
const int arrLength = 20;? ?// 數(shù)組長度
double* getStusGrade()
{
? ? // 學(xué)生成績數(shù)組
? ? double gradeArr[arrLength] = {
? ? 60.5, 62.5, 67.5, 40, 50, 60, 70, 80, 90, 100,
? ? 90.5, 12, 13.5, 84, 65, 76, 87, 88, 99, 20.5
? ? };
? ? // 堆內(nèi)存上分配160個字節(jié)的內(nèi)存空間 20×8個字節(jié)
? ? double* arrP = (double*)malloc(arrLength * sizeof(double));
? ? // 將棧內(nèi)存上的數(shù)組數(shù)據(jù)添加到堆內(nèi)存空間中
? ? for (int index = 0; index < arrLength; index++)
? ? {
? ? ? ? arrP[index] = gradeArr[index];
? ? }
? ? return arrP;
}
int main(int argc, char** argv)
{
? ? double* ptr = getStusGrade();
? ? // 輸出學(xué)生成績
? ? for (int index = 0; index < arrLength; index++)
? ? {
? ? ? ? std::cout << "學(xué)生" << index + 1 << "的數(shù)學(xué)成績是:" << ptr[index] << std::endl;
? ? }
? ? free(ptr);
? ? ptr = nullptr;
? ? return 0;
}
查看全部 -
指針變量其實和普通變量沒有什么區(qū)別,一個函數(shù)也是可以正常返回一個指針的。
char * func()
{
? ?char * p = nullptr;
? ?return p;
}
int main(int argc,char **argv)
{
? ?return 0;
}但是我們需要思考的是,什么情況下我們要返回一個指針,返回指針的時候需要我們注意些什么?
通常情況下,我們是希望為函數(shù)外提供一片內(nèi)存,例如,我們可以給函數(shù)外面提供一個數(shù)組。
int * func()
{
? ?int arr[] = {1, 2, 3, 4};
? ?return arr;
}但是這樣寫得話,程序會崩潰掉。原因是,arr 數(shù)組是一個局部變量,在 func 結(jié)束之后,其內(nèi)存就被銷毀掉了。此時在函數(shù)外面對其進(jìn)行操作,自然會出問題。所以,要完成這類操作,我們需要把內(nèi)存分配到堆內(nèi)存上面。
int * func()
{
? ?int * arr = (int *)malloc(4 * sizeof(int));
? ?return arr;
}這樣就沒有問題了,當(dāng)然,既然是分配在了堆內(nèi)存上,就要記得手動銷毀。
int main(int argc,char **argv)
{
? ?int * p = func();
? ?free(p);
? ?return 0;
}查看全部 -
代碼塊中定義的變量被稱之為局部變量。它們在其他函數(shù)的語句中是不可見的,也無法訪問它們。
全局變量是在所有函數(shù)體的外部定義的,程序的所有部分都可以使用。全局變量不受作用域的影響,其生命周期一直到程序的結(jié)束。
int a = 2;
int main(int argc,char **argv)
{
? ?return 0;
}靜態(tài)變量受作用域的影響,其生命周期一直到程序的結(jié)束。
例如:
void func()
{
? ?static int a = 0;
}我們可以在函數(shù)中申明一個靜態(tài)變量。值得注意的是,這個變量的作用域雖然是在函數(shù)內(nèi),但是他并不會隨著函數(shù)結(jié)束而被銷毀,它會一直存在到程序的結(jié)束。
查看全部
舉報