1、c/c++申請動態內存
? ? ? ?在c++中,申請動態內存是使用new和delete,這兩個關鍵字實際上是運算符,并不是函數。
? ? ? ?而在c中,申請動態內存則是使用malloc和free,這兩個函數是c的標準庫函數,使用它們必須包含stdlib.h,才能編譯通過。
? ? ? ?new/delete和malloc/free的相同之處在于,new和malloc都是手動申請動態內存,釋放時new則需要delete釋放內存,而malloc則需要free釋放內存。
? ? ? ?它們的不同之處在于,new和delete會自動調用對象的構造和析構函數,而malloc/free則只申請內存。
? ? ? ?另外需要注意的是:new的不是數組的話,則直接delete就好,并且只會調用一次析構函數,而new[]的話,則需使用delete[]來釋放,并且數組中每一個元素都會調用一次析構函數,調用完析構函數再釋放內存。
demo如下:
#include <stdlib.h> //malloc用到
#include <string.h> //memset用到
#include <stdio.h> //printf用到
int main()
{
//malloc/free使用
int *pmalloc = (int*)malloc(sizeof(int)*4);
//注意malloc分配的內存一定要進行初始化,否則會出現一些奇怪的問題的哦
memset((void*)pmalloc, 0, sizeof(int)*4);
for(int i = 0; i < 4; i++)
{
pmalloc[i] = i;
printf("pmalloc[%d]=%d\n", i, pmalloc[i]);
}
free(pmalloc);
//new/delete使用
int *pNew = new int;
*pNew = 3;
printf("pnew = %d\n", *pNew);
delete pNew;
//new[]/delete[]使用
int *pNewEx = new int[4];
for(int i = 0; i < 4; i++)
{
pNewEx[i] = i;
printf("pNewEx[%d] = %d\n", i, pNewEx[i]);
}
//此處的[]千萬不能掉,否則會導致內存泄露的
delete[] pNewEx;
return 0;
}
2、c++繼承是什么以及它的優缺點
什么是繼承?
? ? ? ?顧名思義,繼承是一種物體對另外一種物體某些屬性,動作的接續。舉個例子,比如人這個個體,它的屬性包括身高,體重等這些,它的動作則包括吃飯,喝水等等,那么如果另外要定義兩種物體,男人和女人,那么這些屬性和動作就都可以從人這個物體中繼承下來,這,就是繼承。當然,繼承不只是這么簡單,我們后續會陸續說到的。
demo如下:
#include <stdio.h>
class CPerson
{
public:
CPerson()
{
height = 170;
weight = 120;
}
~CPerson(){}
void DrinkWater()
{
printf("喝水\n");
}
void HavingDinner()
{
printf("吃飯\n");
}
int GetHeight()
{
return height;
}
int GetWeight()
{
return weight;
}
private:
int height;
int weight;
};
class CMan : public CPerson
{
public:
CMan(){}
~CMan(){}
};
class CWoman: public CPerson
{
public:
CWoman(){}
~CWoman(){}
};
int main()
{
CMan cMan;
cMan.DrinkWater();
cMan.HavingDinner();
printf("男人身高:%d\n", cMan.GetHeight());
printf("男人體重:%d\n", cMan.GetWeight());
CWoman cWoman;
cWoman.DrinkWater();
cWoman.HavingDinner();
printf("女人身高:%d\n", cWoman.GetHeight());
printf("女人體重:%d\n", cWoman.GetWeight());
return 0;
}
- 優點:類繼承是在編譯時刻靜態定義的,且類繼承可以較方便地改變父類的實現,實現函數的重用。
- 缺點:首先,因為繼承在編譯時刻就定義了,所以無法在運行時改變從父類繼承的實現,其次,父類一般至少定義了子類的部分行為,父類的任何改變都可能影響子類的行為,也就是說,如果繼承下來的實現不適合子類的問題,那么父類必須重寫或者被其他的類替換,這種依賴關系限制了靈活性。
從以上對比看,同一種屬性既可以是優點,從另外的方面來講,又是缺點,就看個人在編程過程中的靈活運用了。
3、c++的三大特性
? ? ? ?封裝、繼承、多態。
- 封裝是一種技術,它使類的定義和實現分離;
- 繼承,從廣義上講,繼承有三種實現方式,其一,為實現繼承,指使用基類的屬性和方法而無需額外編碼,其二,可視繼承,即子窗體使用父窗體的外觀和實現代碼,其三,則為接口繼承,即僅僅繼承屬性和方法,實現則滯后到子類去實現,也就是父類使用的是純虛函數,或者重寫父類接口方法,則是虛函數,例如多態的實現就使用了接口繼承。
- 多態,簡單來講,就是父類定義了虛函數,子類重新實現該函數,那么當父類指針指向子類時,會調用子類的該方法,這,就是多態。
下面是多態的demo:
#include <stdio.h>
#include <string.h>
class CPerson
{
public:
CPerson()
{
height = 170;
weight = 120;
memset(sex, 0, sizeof(sex));
}
~CPerson(){}
virtual void SetSex() = 0;
void PrintSex()
{
printf("我的性別是:%s\n", sex);
}
private:
int height;
int weight;
//此處sex不能是私有,否則子類中無法使用,因為子類對父類的私有成員有繼承權,但沒有使用權,也就是只能看,不能摸
protected:
char sex[8];
};
class CMan : public CPerson
{
public:
CMan(){}
~CMan(){}
void SetSex()
{
strncpy(sex, "男人", sizeof(sex)-1);
}
};
class CWoman: public CPerson
{
public:
CWoman(){}
~CWoman(){}
void SetSex()
{
strncpy(sex, "女人", sizeof(sex)-1);
}
};
int main()
{
CPerson* pPerson = new CMan;
pPerson->SetSex();
pPerson->PrintSex();
delete pPerson;
CPerson* pPerson0 = new CWoman;
pPerson0->SetSex();
pPerson0->PrintSex();
delete pPerson0;
return 0;
}
4、子類和父類調用構造函數和析構函數的先后順序
- 子類對象定義時,先調用父類的構造函數,再調用子類的構造函數;
- 子類對象銷毀時,如果父類析構函數是虛函數,那么先調用子類的析構函數,再調用父類的析構函數,否則只會調用父類的析構函數;
demo如下:
#include <stdio.h>
class CPerson
{
public:
CPerson()
{
printf("建立父類\n");
}
//注意,父類析構函數一定要是虛函數,這樣銷毀子類時才會先調用子類的析構函數
virtual ~CPerson()
{
printf("銷毀父類\n");
}
};
class CMan : public CPerson
{
public:
CMan()
{
printf("建立子類\n");
}
~CMan()
{
printf("銷毀子類\n");
}
};
int main()
{
CPerson* pPerson = new CMan;
delete pPerson;
return 0;
}
執行結果如下:
建立父類
建立子類
銷毀子類
銷毀父類
5、什么是引用
引用,其實就是給變量取了一個別名,聲明引用時要切記初始化,且引用本身不占存儲單元,純粹就是變量多了一個名稱而已。
demo如下:
#include <stdio.h>
void setValue(int & p_iValue)
{
p_iValue = 10;
}
void setValue1(int p_iValue)
{
p_iValue = 9;
}
int main()
{
int iValue = 8;
int iValue1 = 8;
setValue(iValue);
printf("value=%d\n", iValue); //結果為10
setValue1(iValue1);
printf("value1=%d\n", iValue1); //結果還是8
return 0;
}
6、將引用作為函數參數有哪些特點
- 一是,使用引用傳遞參數是直接對實參本身進行操作,當需要在函數內部修改傳遞進來的變量并傳出去時,可使用引用;
- 二來,引用是無需重新分配存儲空間的,但指針卻需要,所以有時使用引用會更有效率;
7、什么時候需要使用常引用
? ? ? ?當既要使用引用提高程序的效率,又不能在函數內部修改實參的值時,可使用常引用。
8、將引用作為函數返回值類型的好處和需遵循的規則
? ? ? ?好處:在內存中不產生被返回值的副本
? ? ? ?需遵循的規則:
? ? ? ?(1)不能返回局部變量的引用;
? ? ? ? (2)不能返回函數內部動態分配的變量的引用,因為引用只是作為一個臨時變量的出現,并未賦予一個實際的變量,該引用所指向的空間無法被釋放;
? ? ? ?(3)可以返回類成員的引用,但最好是const類型;
? ? ? ?(4)為了保證連續使用流操作符(<< >>)重載返回值時,操作的是同一個對象,流操作符重載返回值應該聲明為引用
? ? ? ?(5)+-*/這四則運算符不能返回引用
9、引用和多態的關系
? ? ? ?引用是c++中另外一種實現多態的手段,與指針一樣,也是基類的引用可指向派生類的實例。
引用實現多態的demo如下:
#include <stdio.h>
#include <string.h>
class CPerson
{
public:
CPerson()
{
height = 170;
weight = 120;
memset(sex, 0, sizeof(sex));
}
~CPerson(){}
virtual void SetSex()
{
strncpy(sex, "人", sizeof(sex)-1);
}
void PrintSex()
{
printf("我的性別是:%s\n", sex);
}
private:
int height;
int weight;
//此處sex不能是私有,否則子類中無法使用,因為子類對父類的私有成員有繼承權,但沒有使用權,也就是只能看,不能摸
protected:
char sex[8];
};
class CMan : public CPerson
{
public:
CMan(){}
~CMan(){}
void SetSex()
{
strncpy(sex, "男人", sizeof(sex)-1);
}
};
int main()
{
CMan cman;
CPerson *pPerson = &cman;
pPerson->SetSex(); //此處調用的是子類的SetSex
pPerson->PrintSex();
return 0;
}
10、引用和指針的區別
- 指針通過某個指針變量指向某個對象后,對指針所指向的對象間接操作;
- 引用本身就是變量的別名,所以對引用操作就是直接對所指向的變量進行操作;
- 引用不會重新分配存儲空間,但指針卻需要重新分配存儲空間;