- malloc()?函數(shù)在 C 語言中就出現(xiàn)了,在 C++ 中仍然存在,但建議盡量不要使用 malloc() 函數(shù)。new 與 malloc() 函數(shù)相比,其主要的優(yōu)點(diǎn)是,new 不只是分配了內(nèi)存,它還創(chuàng)建了對(duì)象。
//一維數(shù)組動(dòng)態(tài)分配,數(shù)組長度為 m
int *array = new int [m];
//釋放內(nèi)存
delete [] array;
//二維數(shù)組
int **array;
// 假定數(shù)組第一維長度為 m, 第二維長度為 n
// 動(dòng)態(tài)分配空間
array = new int *[m];
for(int i = 0; i < m; ++i)
{
array[i] = new int [n];
}
//釋放
for(int i = 0; i < m; ++i)
{
delete [] array[i];
}
delete [] array;
?
- new 和 malloc 內(nèi)部的實(shí)現(xiàn)方式有什么區(qū)別?new 的功能是在堆區(qū)新建一個(gè)對(duì)象,并返回該對(duì)象的指針。所謂的“新建對(duì)象”的意思就是,將調(diào)用該類的構(gòu)造函數(shù),因?yàn)槿绻粯?gòu)造的話,就不能稱之為一個(gè)對(duì)象。而 malloc 只是機(jī)械的分配一塊內(nèi)存,如果用 malloc 在堆區(qū)創(chuàng)建一個(gè)對(duì)象的話,是不會(huì)調(diào)用構(gòu)造函數(shù)的。嚴(yán)格說來用 malloc 不能算是新建了一個(gè)對(duì)象,只能說是分配了一塊與該類對(duì)象匹配的內(nèi)存而已,然后強(qiáng)行把它解釋為“這是一個(gè)對(duì)象”。同樣的,用 delete 去釋放一個(gè)堆區(qū)的對(duì)象,會(huì)調(diào)用該對(duì)象的析構(gòu)函數(shù)。用 free 去釋放一個(gè)堆區(qū)的對(duì)象,不會(huì)調(diào)用該對(duì)象的析構(gòu)函數(shù)。做個(gè)簡(jiǎn)單的實(shí)驗(yàn)即可明了:
#include <iostream>
#include <malloc.h>
class TEST
{
private:
int num1;
int num2;
public:
TEST()
{
num1 = 10;
num2 = 20;
}
void Print()
{
std::cout << num1 << " " << num2 << std::endl;
}
};
int main(void)
{
// 用malloc()函數(shù)在堆區(qū)分配一塊內(nèi)存空間,然后用強(qiáng)制類型轉(zhuǎn)換將該塊內(nèi)存空間
// 解釋為是一個(gè)TEST類對(duì)象,這不會(huì)調(diào)用TEST的默認(rèn)構(gòu)造函數(shù)
TEST * pObj1 = (TEST *)malloc(sizeof(TEST));
pObj1->Print();
// 用new在堆區(qū)創(chuàng)建一個(gè)TEST類的對(duì)象,這會(huì)調(diào)用TEST類的默認(rèn)構(gòu)造函數(shù)
TEST * pObj2 = new TEST;
pObj2->Print();
return 0;
}
/*
運(yùn)行結(jié)果:
-----------------------------
-842150451 -842150451 |
10 20 |
請(qǐng)按任意鍵繼續(xù). . . |
-----------------------------
我們可以看到pObj1所指的對(duì)象中,字段num1與num2都是垃圾值
而pObj2所指的對(duì)象中,字段num1與num2顯然是經(jīng)過了構(gòu)造后的值
*/
?
類型轉(zhuǎn)換
類型轉(zhuǎn)換是將一個(gè)數(shù)據(jù)類型的值轉(zhuǎn)換為另一種數(shù)據(jù)類型的值。C++ 中有四種類型轉(zhuǎn)換:靜態(tài)轉(zhuǎn)換、動(dòng)態(tài)轉(zhuǎn)換、常量轉(zhuǎn)換和重新解釋轉(zhuǎn)換。
- 靜態(tài)轉(zhuǎn)換(Static Cast):靜態(tài)轉(zhuǎn)換是將一種數(shù)據(jù)類型的值強(qiáng)制轉(zhuǎn)換為另一種數(shù)據(jù)類型的值。靜態(tài)轉(zhuǎn)換通常用于類型相似的對(duì)象之間的轉(zhuǎn)換,例如將 int 類型轉(zhuǎn)換為 float 類型。靜態(tài)轉(zhuǎn)換不進(jìn)行任何運(yùn)行時(shí)類型檢查,因此可能會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。
int i = 10;
float f = static_cast<float>(i); // 靜態(tài)將int類型轉(zhuǎn)換為float類型
- 動(dòng)態(tài)轉(zhuǎn)換(Dynamic Cast):動(dòng)態(tài)轉(zhuǎn)換通常用于將一個(gè)基類指針或引用轉(zhuǎn)換為派生類指針或引用。動(dòng)態(tài)轉(zhuǎn)換在運(yùn)行時(shí)進(jìn)行類型檢查,如果不能進(jìn)行轉(zhuǎn)換則返回空指針或引發(fā)異常。
class Base {};
class Derived : public Base {};
Base* ptr_base = new Derived;
// 將基類指針轉(zhuǎn)換為派生類指針
Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base);
- 常量轉(zhuǎn)換(Const Cast):常量轉(zhuǎn)換用于將 const 類型的對(duì)象轉(zhuǎn)換為非 const 類型的對(duì)象。常量轉(zhuǎn)換只能用于轉(zhuǎn)換掉 const 屬性,不能改變對(duì)象的類型。
const int i = 10;
int& r = const_cast<int&>(i); // 常量轉(zhuǎn)換,將const int轉(zhuǎn)換為int
- 重新解釋轉(zhuǎn)換(Reinterpret Cast):重新解釋轉(zhuǎn)換將一個(gè)數(shù)據(jù)類型的值重新解釋為另一個(gè)數(shù)據(jù)類型的值,通常用于在不同的數(shù)據(jù)類型之間進(jìn)行轉(zhuǎn)換。重新解釋轉(zhuǎn)換不進(jìn)行任何類型檢查,因此可能會(huì)導(dǎo)致未定義的行為。
int i = 10;
float f = reinterpret_cast<float&>(i); // 重新解釋將int類型轉(zhuǎn)換為float類型
?
typedef 與 #define 的區(qū)別
- 執(zhí)行時(shí)間不同:關(guān)鍵字 typedef 在編譯階段有效,由于是在編譯階段,因此 typedef 有類型檢查的功能。#define 則是宏定義,發(fā)生在預(yù)處理階段,也就是編譯之前,它只進(jìn)行簡(jiǎn)單而機(jī)械的字符串替換,而不進(jìn)行任何檢查。
typedef unsigned int UINT;
void func()
{
UINT value = "abc"; // error C2440: 'initializing' : cannot convert from 'const char [4]' to 'UINT'
cout << value << endl;
}
- 功能有差異:typedef 用來定義類型的別名,定義與平臺(tái)無關(guān)的數(shù)據(jù)類型,與 struct 的結(jié)合使用等。#define 不只是可以為類型取別名,還可以定義常量、變量、編譯開關(guān)等。
- 作用域不同:#define 沒有作用域的限制,只要是之前預(yù)定義過的宏,在以后的程序中都可以使用。
void func1()
{
#define HW "HelloWorld";
}
void func2()
{
string str = HW;
cout << str << endl;
}
而typedef有自己的作用域
void func1()
{
typedef unsigned int UINT;
}
void func2()
{
UINT uValue = 5; //error C2065: 'UINT' : undeclared identifier
}
?
class A
{
typedef unsigned int UINT;
UINT valueA;
A() : valueA(0){}
};
class B
{
UINT valueB;
//error C2146: syntax error : missing ';' before identifier 'valueB'
//error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
};
上面例子在B類中使用UINT會(huì)出錯(cuò),因?yàn)閁INT只在類A的作用域中。此外,在類中用typedef定義的類型別名還具有相應(yīng)的訪問權(quán)限:
class A
{
typedef unsigned int UINT;
UINT valueA;
A() : valueA(0){}
};
void func3()
{
A::UINT i = 1;
// error C2248: 'A::UINT' : cannot access private typedef declared in class 'A'
}
而給UINT加上public訪問權(quán)限后,則可編譯通過。
class A
{
public:
typedef unsigned int UINT;
UINT valueA;
A() : valueA(0){}
};
void func3()
{
A::UINT i = 1;
cout << i << endl;
}
- 對(duì)指針的操作:二者修飾指針類型時(shí),作用不同:
typedef int * pint;
#define PINT int *
int i1 = 1, i2 = 2;
const pint p1 = &i1; //p不可更改,p指向的內(nèi)容可以更改,相當(dāng)于 int * const p;
const PINT p2 = &i2; //p可以更改,p指向的內(nèi)容不能更改,相當(dāng)于 const int *p;或 int const *p;
pint s1, s2; //s1和s2都是int型指針
PINT s3, s4; //相當(dāng)于int * s3,s4;只有一個(gè)是指針。
void TestPointer()
{
cout << "p1:" << p1 << " *p1:" << *p1 << endl;
//p1 = &i2; //error C3892: 'p1' : you cannot assign to a variable that is const
*p1 = 5;
cout << "p1:" << p1 << " *p1:" << *p1 << endl;
cout << "p2:" << p2 << " *p2:" << *p2 << endl;
//*p2 = 10; //error C3892: 'p2' : you cannot assign to a variable that is const
p2 = &i1;
cout << "p2:" << p2 << " *p2:" << *p2 << endl;
}
結(jié)果:
p1:00EFD094 *p1:1
p1:00EFD094 *p1:5
p2:00EFD098 *p2:2
p2:00EFD094 *p2:5
- 還可以用 typedef 來定義與平臺(tái)無關(guān)的類型。比如定義一個(gè)叫 FALSE 的浮點(diǎn)類型,在目標(biāo)平臺(tái)一上,讓它表示最高精度的類型為:
typedef long double FALSE;
在不支持 long double 的平臺(tái)二上,改為:
typedef double FALSE;
在連 double 都不支持的平臺(tái)三上,改為:
typedef float FALSE;
也就是說,當(dāng)跨平臺(tái)時(shí),只要改下 typedef 本身就行,不用對(duì)其他源碼做任何修改。標(biāo)準(zhǔn)庫就廣泛使用了這個(gè)技巧,比如 size_t。
- 另外,因?yàn)?typedef 是定義了一種類型的新別名,不是簡(jiǎn)單的字符串替換,所以它比宏來得穩(wěn)?。m然用宏有時(shí)也可以完成以上的用途)。為了方便枚舉的使用,應(yīng)該和 typedef 結(jié)合使用,例如:
typedef enum BAYER_PATTERN{
BAYER_RG = 0,
BAYER_BG,
BAYER_GR,
BAYER_GB
}BAYER_PATTERN;
使用的時(shí)候就不用再?enum BAYER_PATTERN color = BAYER_RG;?了,而可以直接用:
BAYER_PATTERN color = BAYER_RG;
?
- 不帶初始化的定義:帶有靜態(tài)存儲(chǔ)持續(xù)時(shí)間的變量會(huì)被隱式初始化為 NULL(所有字節(jié)的值都是 0),其他所有變量的初始值是未定義的。
?
- C/C++ 編譯 cpp 文件是從上往下編譯,所以 main 函數(shù)里面調(diào)用其他函數(shù)時(shí),如果其他函數(shù)在 main 函數(shù)的下面,則要在 main 函數(shù)上面先聲明這個(gè)函數(shù)。或者把 main 函數(shù)放在最下面,這個(gè)不僅限于 main 函數(shù),其他函數(shù)的調(diào)用都是如此。被調(diào)用的函數(shù)要在調(diào)用的函數(shù)之前聲明。
// 函數(shù)聲明
int func();
int main()
{
// 函數(shù)調(diào)用
int i = func();
}
// 函數(shù)定義
int func()
{
return 0;
}
?
- 若參與運(yùn)算的類型不同,則先轉(zhuǎn)換成同一類型,然后進(jìn)行運(yùn)算。轉(zhuǎn)換按數(shù)據(jù)長度增加的方向進(jìn)行,以保證精度不降低。如int型和long型運(yùn)算時(shí),先把int量轉(zhuǎn)成long型后再進(jìn)行運(yùn)算。若兩種類型的字節(jié)數(shù)不同,轉(zhuǎn)換成字節(jié)數(shù)高的類型。若兩種類型的字節(jié)數(shù)相同,且一種有符號(hào),一種無符號(hào),則轉(zhuǎn)換成無符號(hào)類型。
?
- 所有的浮點(diǎn)運(yùn)算都是以雙精度進(jìn)行的,即使僅含float單精度值運(yùn)算的表達(dá)式,也要先轉(zhuǎn)換成double型,再作運(yùn)算。
?
- char型和short型參與運(yùn)算時(shí),必須先轉(zhuǎn)換成int型。
?
- 在賦值運(yùn)算中,賦值號(hào)兩邊量的數(shù)據(jù)類型不同時(shí),賦值號(hào)右邊量的類型將轉(zhuǎn)換為左邊量的類型。如果右邊量的數(shù)據(jù)類型長度比左邊長時(shí),將丟失一部分?jǐn)?shù)據(jù),這樣會(huì)降低精度:
int a=1;
double b=2.5;
a=b;
cout << a; //輸出為 2,丟失小數(shù)部分
int a = 1;
double b = 2.1;
cout << "a + b = " << a + b << endl; //輸出為a + b = 3.1
?
文章來源:http://www.zghlxwxcb.cn/news/detail-841071.html
掃碼關(guān)注公眾號(hào),查看更多精彩內(nèi)容文章來源地址http://www.zghlxwxcb.cn/news/detail-841071.html
到了這里,關(guān)于C++學(xué)習(xí)筆記——003的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!