第一篇:黑馬程序員C語言教程: cc++專家_交你如何使用c++中的類型轉換
傳智播客C/C++專家– 交你如何使用c++中的類型轉換
關于C風格的強制類型轉換是程序猿用的最多的一種轉換方式, 不管什么類型的轉換統統都是TYTE b =(TYPE)a。但是眾所周知C++程序中對類型的檢測非常嚴格,如果類型轉換過程中使用C風格的類型轉換就容易出現一些問題。所以今天傳智播客C/C++專家在這里給大家介紹一下C++風格的類型轉換的幾種轉換操作符以及使用場合。
C++風格的類型轉換提供了4種類型轉換操作符: const_cast,static_cast,dynamic_cast,reinterpret_cast 4種類型轉換的格式,如:TYPE B = static_cast(TYPE)(a)。? const_cast ? 去掉類型的const或volatile屬性。
struct SA { int i;};const SA ra;//ra.i = 10;
//直接修改const類型,編譯錯誤
SA &rb = const_cast
rb.i =10;? static_cast 類似于C風格的強制轉換。主要應用場景:
? 基類和子類之間轉換:其中子類指針轉換成父類指針是安全的;但父類指針轉換成子類指針是不安全的。(基類和子類之間的動態類型轉換建議用dynamic_cast)? 基本數據類型轉換。
enum, struct, int, char, float等。static_cast不能進行無關類型(如非基類和子類)指針之間的轉換。? 把空指針轉換成目標類型的空指針。? 把任何類型的表達式轉換成void類型。
? static_cast不能去掉類型的const、volitale屬性(用const_cast)。
int n =6;// 基本類型轉換
double d = static_cast
? dynamic_cast
有條件轉換、動態類型轉換,運行時會進行類型安全檢查(轉換失敗返回NULL):
? 安全的基類和子類之間轉換。? 必須要有虛函數。
? 相同基類不同子類之間的交叉轉換。但結果是NULL。class ItcastClass { public: int m_iNum;//基類必須有虛函數。保持多臺特性才能使用dynamic_cast virtualvoid foo(){};};
class HeiMaClass: public ItcastClass { public: char*m_szName[100];void bar(){};};
ItcastClass* pb =new HeiMaClass();
//子類->父類,靜態類型轉換,正確但不推薦 HeiMaClass *pd1 = static_cast
HeiMaClass *pd2 = dynamic_cast
HeiMaClass *pd21 = static_cast
? 轉換的類型必須是一個指針、引用、算術類型、函數指針或者成員指針。
? 在比特位級別上進行轉換。它可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針(先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還可以得到原先的指針值)。但不能將非32bit的實例轉成指針。? 最普通的用途就是在函數指針類型之間進行轉換。? 很難保證移植性。
int doSomething(){return0;};
//FuncPtr 是一個指向函數的指針,該函數沒有參數,返回 值類型為 void typedef void(*FuncPtr)();//10個FuncPtrs指針的數組 讓我們假設你希望(因為某些莫 名其妙的原因)把一個指向下面函數的指針存 入funcPtrArray數組: FuncPtr funcPtrArray[10];
// 編譯錯誤!類型不匹配,reinterpret_cast可以讓編譯器以你 的方法去看待它們:funcPtrArray funcPtrArray[0] =&doSomething;//不同函數指針類型之間進行轉換
funcPtrArray[0]=reinterpret_cast
? 多態類之間的類型轉換用daynamic_cast。? 不同類型的指針類型轉換用reinterpret_cast。今天的內容就到這里, 祝大家學習愉快!
第二篇:黑馬程序員C語言教程: CC++培訓專家-預處理命令使用詳解
傳智播客C/C++培訓專家:預處
理命令詳解
作為一枚C/C++程序猿,在我們編寫和查看C/C++源代碼的過程中會遇到各種編譯指令,這些指令稱為預處理命令。預處理命令雖然不是C/C+的一部分,但卻擴展了C程序的設計環境,下面傳智播客C/C+培訓專家將向大家介紹如何應用預處理程序和注釋簡化程序開發過程,并提高程序的可讀性。
ANSI標準定義的C語言所有預處理命令均以符號#開頭,比如我寫程序時常用的:
#define,#undef,#include,#if,#else,#elif,#endif,#ifdef,#ifndef, #error 1.#define和 #undef 宏定義命令的一般形式為:
#define[MacroName][MacroValue],示例如下: #defineITHEIMA 傳智播客黑馬程序員
在源程序中每次遇到ITHEIMA時,均以定義的值傳智播客黑馬程序員代換它。
? 在使用該宏時,有以下幾點注意事項:
? 該語句沒有分號。在標識符和串之間可以有任意個空格。? 定義宏的時候,可以使用之前已經定義好的宏。
? 如果串長于一行,可以在該行末尾用一反斜杠' '續行。
#defineLONG_STRING“good good study,day day up!” ? 在定義宏標識符時,字母一般需要大寫。? 預處理運算符的使用:
? #--該符號是“字符串化”的意思,出現在宏定義中的#是把跟在后面的參數轉換成一個字符串
#define ERROR_LOG(module)
fprintf(stderr, “error: ”#module“n”)ERROR_LOG(“add”);轉換為 fprintf(stderr,“error: ”add“n”);ERROR_LOG(devied =0);轉換為 fprintf(stderr,“error: devied=0n”);? ##--是連接符號,將多個串連接到一起。char *szStr = “傳播播客_黑馬程序員”;#define ITCAST(exp)cout < 2.#include 命令#i nclude使編譯程序將另一源文件嵌入帶有#include的源文件,被讀入的源文件必須用雙引號或尖括號括起來。例如: #include“stdio.h”或者#include 這兩行代碼均使用C編譯程序讀入并編譯用于處理磁盤文件庫的子程序。將文件嵌入#i nclude命令中的文件內是可行的,這種方 式稱為嵌套的嵌入文件,嵌套層次依賴于具體實現。 ? 如果顯式路徑名為文件標識符的一部分,則僅在那些子目錄中搜索被嵌入文件。 例如: #include “../include/head.h” ? 如果文件名用雙引號括起來,則首先檢索當前工作目錄。如果未發現文件,則在命令行中說明的所有目錄中搜索。如果仍未發現文件,則搜索實現時定義的標準目錄。例如: include “head.h” ? 如果文件名被尖括號括起來,則首先在編譯命令行中的目錄內檢索。如果文件沒找到,則檢索標準目錄,不檢索當前工作目錄。 例如: include
它與#endif之間的代碼,否則跳過這些代碼。命令#endif標識一個#if塊的結束。
跟在#if后面的表達式在編譯時求值,因此它必須僅含常量及已定義過的標識符,不可使用變量。表達式不許含有操作符sizeof(sizeof也是編譯時求值)。
? #else命令的功能有點象C語言中的else;#else建立另一選擇(在#if失敗的情況下)。注意,#else屬于#if塊。
? #elif命令意義與ELSE IF 相同,它形成一個if else-if階梯狀語句,可進行多種編譯選擇。#elif 后跟一個常量表達式。如果表達式為true,則編譯其后的代碼塊,不對其它#elif表達式進行測試。否則,順序測試下一塊。?
4.#error 命令#error強迫編譯程序停止編譯,主要用于程序調試。該指令使預處理器發出一條錯誤消息,該消息包含指令中的文本.這條指令的目的就是在程序崩潰之前能夠給出一定的信息。
5.#ifdef 和 #ifndef 條件編譯的另一種方法是用#ifdef與#ifndef命令,它們分別表示“如果有定義”及“如果無定義”。# ifdef的一般形式是:
# ifdef macroname statement sequence
#endif #ifdef與#ifndef可以用于#if、#else,#elif語句中,但必須與一個#endif。
define MAX 91 #include
int main(){ #ifdef MAX cout<<“hello,MAX!”< #else cout<<“where is MAX?”< #endif #ifndef LEO cout<<“LEO is not defined”< #endif return 0;} 今天關于預處理命令的知識點傳智播客C/C+培訓專家就為大家接受到這里, 歡迎大家留言交流.
第三篇:黑馬程序員C語言教程: CC++培訓專家:漫談軟件編碼風格
傳智播客C/C++培訓專家:漫談軟件編碼風格
通過建立代碼編寫規范,形成開發小組編碼約定,提高程序的可靠性、可讀性、可修改性、可維護性、一致性,保證程序代碼的質量,繼承軟件開發成果,充分利用資源。提高程序的可繼承性,使開發人員之間的工作成果可以共享。代碼的風格主要有以下幾點:
1、縮進
縮進以4個空格為單位。預處理語句、全局數據、函數原型、標題、附加說明、函數說明、標號等均頂格書寫。語句塊的“{”“}”配對對齊,并與其前一行對齊,語句塊類的語句縮進建議每個“{”“}”單獨占一行。
2、空格
變量、類、常量數據和函數在其類型,修飾(如 __fastcall 等)名稱之間適當空格并據情況對齊。關鍵字原則上空一格,如: if(...)等,運算符的空格規定如下:“::”、“->”、“[”、“]”、“++”、“--”、“~”、“!”、“+”、“-”(指正負號),“&”(取址或引用)、“*”(指使用指針時)等幾個運算符兩邊不加空格(其中單目運算符系指與操作數相連的一邊),其它運算符(包括大多數二目運算符和三目運算符“?:”兩邊均加一空格,“(”、“)”運算符在其內側空一格,在作函
數定義時還可據情況多空或不空格來對齊,但在函數實現時可以不用?!?”運算符只在其后空一格,需對齊時也可不空或多空格,“sizeof”運算符建議也在其后空一格,不論是否有括號,對語句行后加的注釋應用適當空格與語句隔開并盡可能對齊。
3、對齊
原則上關系密切的行應對齊,對齊包括類型、修飾、名稱、參數等各部分對齊。另每一行的長度不應超過屏幕太多,必要時適當換行,換行時盡可能在“,”處或運算符處,換行后最好以運算符打頭,并且以下各行均以該語句首行縮進,但該語句仍以首行的縮進為準,即如其下一行為“{”應與首行對齊。
變量定義最好通過添加空格形成對齊,同一類型的變量最好放在一起。
4、空行
程序文件結構各部分之間空兩行,若不必要也可只空一行,各函數實現之間一般空兩行,由于BCB會自動產生一行“//------”做分隔,另因每個函數還要有函數說明注釋,故通常只需空一行或不空,但對于沒有函數說明的情況至少應再空一行。對自己寫的函數,建議也加上“//------”做分隔。函數內部數據與代碼之間應空至少一行,代碼中適當處應以空行空開,建議在代碼中出現變量聲明時,在其前空一行。類中四個“p”之間至少空一行,在其中的數據與函數之間也應空行。
5、注釋
對注釋有以下三點要求: A.必須是有意義。B.必須正確的描述了程序。C.必須是最新的。
注釋必不可少,但也不應過多,以下是四種必要的注釋: A.標題、附加說明。
B.函數說明。對幾乎每個函數都應有適當的說明,通常加在函數實現之前,在沒有函數實現部分的情況下則加在函數原型前,其內容主要是函數的功能、目的、算法等說明,參數說明、返回值說明等,必要時還要有一些如特別的軟硬件要求等說明。C.在代碼不明晰或不可移植處必須有一定的說明。D.及少量的其它注釋。
注釋有塊注釋和行注釋兩種,分別是指:“/**/”和“//”建議對A用塊注釋,D用行注釋,B、C則視情況而定,但應統一,至少在一個單元中B類注釋形式應統一。
6、代碼長度:
對于每一個函數建議盡可能控制其代碼長度為53行左右,超過53行的代碼要重新考慮將其拆分為兩個或兩個以上的函數。函數拆分規則應該一不破壞原有算法為基礎,同時拆分出來的部分應該是可以重復利用的。對于在多個模塊或者窗體中都要用到的重復性代碼,完全可以將起獨立成為一個具備公用性質的函數,放置于一個公用模塊中(Common.cpp/Common.h)。
第四篇:黑馬程序員C語言教程: CC++培訓專家-編寫高效C語言的四大絕招
傳智播客C/C++培訓專家:編寫高效C語言的四大絕招
C語言是很多程序猿的入門語言,而且C語言也是一門用不過時的語言。編寫高效簡潔的C語言代碼,是許多軟件工程師追求的目標。今天傳智播客C/C++培訓專家針對編程工作中的一些體會和經驗給大家做相關的闡述。
第一招:以空間換時間
計算機程序中最大的矛盾是空間和時間的矛盾,那么,從這個角度出發逆向思維來考慮程序的效率問題,我們就有了解決問題的第1招--以空間換時間。比如說字符串的賦值: 方法A:通常的辦法 #define LEN 32 char string1 [LEN];memset(string1, 0, LEN);strcpy(string1, “This is a example!”);方法B:
const char string2[LEN] =“This is a example!”;char * cp;cp = string2;
從上面的例子可以看出,A和B的效率是不能比的。在同樣的存儲空間下,B直接使用指針就可以操作了,而A需要調用兩個字符函數才能完成。B的缺點在于靈活性沒有A好。在需要頻繁更改一個字符串內容的時候,A具有更好的靈活性;如果采用方法B,則需要預存許多字符串,雖然占用了大量的內存,但是獲得了程序執行的高效率。
第二招:數學方法解決問題
現在我們演繹高效C語言編寫的第二招--采用數學方法來解決問題。數學是計算機之母,沒有數學的依據和基礎,就沒有計算機的發展,所以在編寫程序的時候,采用一些數學方法會對程序的執行效率有數量級的提高。舉例如下,求 1~100的和。方法C: int I , j;for(I = 1;I<=100;I ++){ j += I;} 方法D int I;I =(100 *(1+100))/ 2;
這個例子是我印象最深的一個數學用例,是我的計算機啟蒙老師考我的。當時我只有小學三年級,可惜我當時不知道用公式 N×(N+1)
/ 2 來解決這個問題。方法E循環了100次才解決問題,也就是說最少用了100個賦值,100個判斷,200個加法(I和j);而方法F僅僅用了1個加法,1 次乘法,1次除法。效果自然不言而喻。所以,現在我在編程序的時候,更多的是動腦筋找規律,最大限度地發揮數學的威力來提高程序運行的效率。
第三招:使用位操作
實現高效的C語言編寫的第三招——使用位操作。減少除法和取模的運算。在計算機程序中數據的位是可以操作的最小數據單位,理論上可以用“位運算”來完成所有的運算和操作。一般的位操作是用來控制硬件的,或者做數據變換使用,但是,靈活的位操作可以有效地提高程序運行的效率。舉例如下: 方法E int I,J;I = 257 /8;J = 456 % 32;方法F int I,J;I = 257 >>3;J = 456-(456 >> 4 << 4);在字面上好像F比E麻煩了好多,但是,仔細查看產生的匯編代碼就會明白,方法E調用了基本的取模函數和除法函數,既有函數調用,還有很多匯編代碼和寄存器參與運算;而方法F則僅僅是幾句相關的匯編,代碼更簡潔,效率更高。當然,由于編譯器的不同,可能效率的差距不大,但是,以我目前遇到的MS C ,ARM C 來看,效率的差距還是不小。相關匯編代碼就不在這里列舉了。
運用這招需要注意的是,因為CPU的不同而產生的問題。比如說,在PC上用這招編寫的程序,并在PC上調試通過,在移植到一個16位機平臺上的時候,可能會產生代碼隱患。所以只有在一定技術進階的基礎下才可以使用這招。用移位實現乘除法運算
a=a*4;
b=b/4;
可以改為:
a=a<<2;
b=b>>2;
說明:
除2 = 右移1位 乘2 = 左移1位
除4 = 右移2位 乘4 = 左移2位
除8 = 右移3位 乘8 = 左移3位
......通常如果需要乘以或除以2的n次方,都可以用移位的方法代替。大部分的C編譯器,用移位的方法得到代碼比調用乘除法子程序生成的代碼效率高。
第四招:匯編嵌入
高效C語言編程的必殺技,第四招——嵌入匯編?!霸谑煜R編語言的人眼里,C語言編寫的程序都是垃圾”。這種說法雖然偏激了一些,但是卻有它的道理。匯編語言是效率最高的計算機語言,但是,不可能靠著它來寫一個操作系統吧?所以,為了獲得程序的高效率,我們只好采用變通的方法--嵌入匯編,混合編程。舉例如下,將數組一賦值給數組二,要求每一字節都相符。char string1[1024],string2[1024];方法G int i;for(i =0;i<1024;i++)*(string2 + i)= *(string1 + i)方法H #ifdef _PC_ int I;for(I =0;I<1024;I++)*(string2 + I)= *(string1 + I);#else #ifdef _ARM_ __asm
{ MOV R0,string1 MOV R1,string2 MOV R2,#0 loop: LDMIA R0!, [R3-R11] STMIA R1!, [R3-R11] ADD R2,R2,#8 CMP R2, #400 BNE loop } #endif 方法G是最常見的方法,使用了1024次循環;方法H則根據平臺不同做了區分,在ARM平臺下,用嵌入匯編僅用128次循環就完成了同樣的操作。這里有朋友會說,為什么不用標準的內存拷貝函數呢?這是因為在源數據里可能含有數據為0的字節,這樣的話,標準庫函數會提前結束而不會完成我們要求的操作。這個例程典型應用于LCD數據的拷貝過程。根據不同的CPU,熟練使用相應的嵌入匯編,可以大大提高程序執行的效率。
雖然是必殺技,但是如果輕易使用會付出慘重的代價。這是因為,使用了嵌入匯編,便限制了程序的可移植性,使程序在不同平臺移植的過程中,臥虎藏龍,險象環生!同時該招數也與現代軟件工程的思想相違背,只有在迫不得已的情況下才可以采用。
今天分享到這里,大家有遇到什么問題可以向“傳智播客C/C++培訓專家”留言哦!
第五篇:黑馬程序員C語言教程:QSignalMapper的使用
QSignalMapper信號轉發器的使用 適用范圍
簡單的理解,可以把SignalMapper這個類看成是信號的翻譯和轉發器,它可以把一個無參數的信號翻譯成帶int參數、QString參數、QObject*參數或者QWidget*參數的信號,并將之轉發。這么一說大家有沒有聯想到該類的適用范圍呢?比如說:我有一堆的button,可以把clicked事件放在一個函數里處理,只要給button編個號或者給button起個名就行了,這樣就不用給每個button寫一個slot了,豈不是很方便?
使用方法
? 首先把原始的信號連接到QSignalMapper類的map()槽函數,這樣QSignalMapper能在第一時間接收到原始信號;
? 其次調用setMapping方法建立映射關系,告訴QSignalMapper對象怎樣去處理原始信號。(映射關系通過對應一個整數、字符串或者QWidget*實現)
? 最后通過接收QSignalMapper類轉化后的帶參信號mapped()與槽函數連接,在槽函數中獲得需要的數據,并作出對應的處理。
? 映射的關系可以通過removeMappings()被移除。
示例:
// 頭文件
classWidget:publicQWidget { Q_OBJECT
public: explicitWidget(QWidget*parent=0);~Widget();
publicslots: //自定義槽函數
voidslotClicked(QStringtext);
private: Ui::Widget*ui;QSignalMapper*signalMapper;};// 源文件
Widget::Widget(QWidget*parent): QWidget(parent), ui(newUi::Widget){ ui->setupUi(this);
QStringListtextList;signalMapper=newQSignalMapper(this);// 布局管理器
QVBoxLayout*vLayout=newQVBoxLayout(this);textList<<“北京”<<“上?!?<“廣州”<<“南京”<<“天津”;for(inti=0;i<5;++i){ // 動態創建按鈕
QPushButton*button=newQPushButton(textList[i]);button->setFixedSize(50,30);//按鈕的信號和QSignalMapper類的map()槽函數關聯
// 原始信號傳遞給signalMapper connect(button,SIGNAL(clicked(bool)),signalMapper,SLOT(map()));//設置signalmapper的轉發規則, 轉發為參數為QString類型的
// 信號,并把textList[i]的內容作為實參傳遞。
signalMapper->setMapping(button,textList[i]);vLayout->addWidget(button);} //將轉發的信號連接到最終的槽函數
connect(signalMapper,SIGNAL(mapped(QString)),this,SLOT(slotClicked(QString)));}
// 自定義槽函數
voidWidget::slotClicked(QStringtext){ QMessageBox::information(this,“ButtonClicked”,text);}
當用戶點擊不同的按鈕,會彈出不同的對話框,對話框中顯示的內容為按鈕的標題。