簡單的總結(jié)一下C++ 新手容易犯的一些編程錯誤,給新人們提供一個參考。
1 有些關(guān)鍵字在 cpp 文件中多寫了
對于 C++ 類,一些關(guān)鍵字只要寫在 .h 中就好,cpp 中就不用再加上了,比如 virtual、static 等關(guān)鍵字,如果在 cpp 中多寫,編譯器會報錯。 比如如下的虛接口與靜態(tài)成員變量的定義,只要在頭文件中聲明就可以了。
class shape
{
virtual Draw();
//...
static int nLevel;
}
2 函數(shù)參數(shù)的默認(rèn)值寫到函數(shù)實(shí)現(xiàn)中了
帶有參數(shù)默認(rèn)值的函數(shù),默認(rèn)值是加在函數(shù)聲明處的,函數(shù)實(shí)現(xiàn)處的參數(shù)是不需要帶上的。 為了方便查看代碼,在函數(shù)實(shí)現(xiàn)處的參數(shù)中,將默認(rèn)值注釋起來。正確的做法是,頭文件中有默認(rèn)值:
BOOL CreateConf( const CString& strConfName, const BOOL bAudio = FALSE );
在函數(shù)實(shí)現(xiàn)處的參數(shù)中不用添加默認(rèn)值:
BOOL CreateConf( const CString& strConfName, const BOOL bAudio/* = FALSE*/ );
{
// ......
}
3 在編寫類的時候,在類的結(jié)尾處忘記添加 ";" 分號了
在類的結(jié)尾處忘記添加分號,編譯會報錯,新人們有可能找了半天也沒找出引起編譯錯誤的原因。 其實(shí)很簡單,在類的結(jié)尾處忘記添加分號了。
class Shape
{
// ...
};
4 只添加了函數(shù)聲明,沒有函數(shù)實(shí)現(xiàn)
在添加類的函數(shù)時,只在類的頭文件中添加了函數(shù)聲明,但在 cpp 中卻沒有添加函數(shù)的實(shí)現(xiàn)。 如果其他地方調(diào)用到該函數(shù),在編譯鏈接的時候會報unresolved external symbol錯誤。因為沒有實(shí)現(xiàn),所有沒有供鏈接使用的 obj 文件。
5 cpp 文件忘記添加到工程中,導(dǎo)致沒有生成供鏈接使用的 obj 文件
在添加 C++ 類時,我們一般會添加 .h 頭文件和一個 .cpp 源文件。結(jié)果忘記把 .cpp 文件添加到工程中了,即沒有參與編譯,沒有生成供鏈接使用的 obj 文件。 如果有代碼調(diào)用到該 C++ 類的接口,則在編譯鏈接的時候會報unresolved external symbol錯誤,即鏈接不到該 C++ 類對應(yīng)的接口。
6 函數(shù)中返回了一個局部變量的地址或者引用
在函數(shù)中返回了一個局部變量的地址或者引用,而這個局部變量在函數(shù)結(jié)束時其生命周期就結(jié)束了,內(nèi)存就被釋放了。 當(dāng)外部訪問到該變量的內(nèi)存,會觸發(fā)內(nèi)存訪問違例的異常,因為該變量的內(nèi)存已經(jīng)釋放了。比如如下的錯誤代碼:
char* GetResult()
{
char chResult[100] = { 0 };
// ......
return chResult;
}
7 忘記將父類中的接口聲明 virtual 函數(shù),導(dǎo)致多態(tài)沒有生效
代碼中本來要借助于 C++ 多態(tài)的虛函數(shù)調(diào)用,調(diào)用子類實(shí)現(xiàn)的接口,結(jié)果忘記在父類中將對應(yīng)的接口聲明為 virtual,導(dǎo)致沒有調(diào)用到子類實(shí)現(xiàn)的函數(shù)。 一定要記住,要實(shí)現(xiàn)多態(tài)下的函數(shù)調(diào)用,父類的相關(guān)接口必須聲明為 virtual。
class Shape()
{
// ...
virtual void Draw();
// ...
}
8 該使用雙指針的地方,卻使用了單指針
有時我們需要調(diào)用一個接口去獲取某些數(shù)據(jù),接口中將數(shù)據(jù)拷貝到傳入的參數(shù)對應(yīng)的內(nèi)存中,此時設(shè)計參數(shù)時會傳入指針或引用。 我們在調(diào)用GetData 之前定義了結(jié)構(gòu)體指針p,并 new 出了對應(yīng)的結(jié)構(gòu)體對象內(nèi)存,應(yīng)該在定義 GetData 接口時應(yīng)該使用雙指針(指針的指針)的,結(jié)果錯寫成了單指針。 有問題的代碼如下:
struct CodecInfo // 編碼信息
{
int nFrameRate;
// ...
}
CodecInfo* pInfo = new CodecInfo;
GetAudioCodecPtr()->GetCodecInfo(pInfo); // 調(diào)用AudioCodec::GetCodecInfo獲取編碼信息
AudioCodec::GetCodecInfo( CodecInfo* pInfo) // 此處的參數(shù)不應(yīng)該使用單指針
{
memcpy(pInfo, m_codecInfo, sizeof(CodecInfo));
}
上面中的AudioCodec::GetCodecInfo接口的參數(shù)不應(yīng)該為單指針,應(yīng)該用雙指針,修改后的代碼應(yīng)該如下:
AudioCodec::GetCodecInfo( CodecInfo** pInfo) // 此處的參數(shù)類型使用雙指針
{
memcpy(*pInfo, m_codecInfo, sizeof(CodecInfo));
}
9 發(fā)布 exe 程序時,忘記將 exe 依賴的 C 運(yùn)行時庫和 MFC 庫帶上
比如新人用 VS-MFC 庫編寫一個測試用的工具軟件,結(jié)果在發(fā)布 release 版本程序時,沒有將程序依賴的 C 運(yùn)行時庫帶上,導(dǎo)致該工具軟件在某些電腦中啟動報錯,提示找不到 C 運(yùn)行時庫: 因為程序中依賴了動態(tài)版本的運(yùn)行時庫和 MFC 庫,在發(fā)布程序時要將這些庫帶上。有些系統(tǒng)中沒有這些庫,程序啟動時就會報找不到庫,就會啟動失敗。
10 應(yīng)該使用深拷貝,卻使用了淺拷貝
本來應(yīng)該要進(jìn)行深拷貝的,卻使用了淺拷貝(直接賦值),導(dǎo)致另個不同生命周期的 C++ 對象指向了同一塊內(nèi)存,一個對象將內(nèi)存釋放后,另一個對象再用到這塊內(nèi)存,就造成了內(nèi)存訪問違例,產(chǎn)生異常。 有個經(jīng)典的 C++ 筆試題,讓我們實(shí)現(xiàn) String 類的相關(guān)函數(shù),其主要目的就是用來考察對深拷貝與淺拷貝的理解的。題目中給出 String類的聲明:
class String{
public:
String();
String(const String & str);
String(const char* str);
String& operator=(String str);
char* c_str() const;
~String();
int size() const;
private:
char* data;
};
讓寫出上述幾個函數(shù)的內(nèi)部實(shí)現(xiàn)。這些函數(shù)的實(shí)現(xiàn)代碼如下:
//普通構(gòu)造函數(shù)
String::String(const char *str)
{
if (str == NULL)
{
m_data = new char[1];// 得分點(diǎn):對空字符串自動申請存放結(jié)束標(biāo)志'?'的,加分點(diǎn):對m_data加NULL判斷
*m_data = '?';
}
else
{
int length = strlen(str);
m_data = new char[length + 1];// 若能加 NULL 判斷則更好
strcpy(m_data, str);
}
}
// String的析構(gòu)函數(shù)
String::~String(void)
{
delete[] m_data; // 或delete m_data;
}
//拷貝構(gòu)造函數(shù)
String::String(const String &other)// 得分點(diǎn):輸入?yún)?shù)為const型
{
int length = strlen(other.m_data);
m_data = new char[length + 1];// 若能加 NULL 判斷則更好
strcpy(m_data, other.m_data);
}
//賦值函數(shù)
String & String::operator = (const String &other) // 得分點(diǎn):輸入?yún)?shù)為const型
{
if (this == &other)//得分點(diǎn):檢查自賦值
return *this;
if (m_data)
delete[] m_data;//得分點(diǎn):釋放原有的內(nèi)存資源
int length = strlen(other.m_data);
m_data = new char[length + 1];//加分點(diǎn):對m_data加NULL判斷
strcpy(m_data, other.m_data);
return *this;//得分點(diǎn):返回本對象的引用
}
-
編程
+關(guān)注
關(guān)注
90文章
3716瀏覽量
97178 -
C++
+關(guān)注
關(guān)注
22文章
2123瀏覽量
77110
原文標(biāo)題:C++:10種新手易犯錯誤
文章出處:【微信號:c-stm32,微信公眾號:STM32嵌入式開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
keil實(shí)現(xiàn)c與c++混合編程
汽車網(wǎng)絡(luò)安全開發(fā)語言選型指南:C/C++/Rust/Java等主流語言對比+Perforce QAC/Klocwork工具支持
十大常見的芯片燒錄錯誤,第5個幾乎人人都遇到過
C語言與C++的區(qū)別及聯(lián)系
C與C++之間的聯(lián)系
C語言和C++之間的區(qū)別是什么
C++程序異常的處理機(jī)制
技能+1!如何在樹莓派上使用C++控制GPIO?
C++ 與 Python:樹莓派上哪種語言更優(yōu)?
避雷!樹莓派初學(xué)者常犯的5個錯誤!
使用英特爾? NPU 插件C++運(yùn)行應(yīng)用程序時出現(xiàn)錯誤:“std::Runtime_error at memory location”怎么解決?
主流的 MCU 開發(fā)語言為什么是 C 而不是 C++?
C++新手容易犯的十個編程錯誤
評論