一、頭檔案和源檔案的差別
1.頭檔案:變量、函數的聲明,類的定義、宏的定義......
源檔案:變量的定義,函數的定義實作
2.單獨的頭檔案不參與編譯,源檔案參與編譯
int a;//變量的定義
int b=10;//變量的定義
extern int c;//變量的聲明
若在頭檔案中定義變量,當多個源檔案包含同一個頭檔案時,會出現變量重定義問題
void fun();//函數的聲明
//--------------------
void fun() //函數的定義
{
cout<<"fun()"<<endl;
}
類在頭檔案中聲明,在源檔案中初始化化時需要添加作用域
//AA.h
class CTest
{
public:
int m_a;
const int m_b;//常量在初始化參數清單進行初始化
static int m_c;//類内定義類外初始化化,但不能在頭檔案中初始化,會出現重定義,應該在源檔案中初始化
CTest();
~CTest();
void fun();
static void fun2();
void fun3() const;
virtual void fun4();
}
//------------------
//AA.cpp
int CTest::m_c=30;//靜态函數在源檔案中初始化
CTest::CTest():m_a(10),m_b(20)
{
cout<<"m_a="<<m_a<<endl;
}
CTest::~CTest(){
cout<<"~CTest()"<<endl;
}
void CTest::fun(){
cout<<"fun()"<<endl;
}
//static要去掉
void CTest::fun2(){
cout<<"fun2"<<endl;
}
//const 要保留
void CTest::fun3() const{
cout<<"fun3"<<endl;
}
//virtual要去掉
void CTest::fun4(){
cout<<"fun3"<<endl;
}
二、頭檔案的重複包含問題
#pragma once//和編譯器溝通,告訴編譯器,目前頭檔案在源檔案中隻包含一次
另一種方法是基于宏的邏輯判斷
#ifndef __宏__
#define __宏__
...頭檔案中的代碼...
#endif
//宏的名字與頭檔案名進行綁定,例如AA.h->__AA_H__
對比:
1.#pragma once 效率高,代碼編譯效率快
2.#pragma once不用擔心宏重名問題
二、程式生成過程
1.預處理:源代碼檔案main.cpp -> main.i預處理後的檔案
(1)#include 頭檔案的展開
(2)删除注釋
(3)#define宏的替換
(4)#ifdef、#ifndef、#endif、#if、#else、#elif等預處理指令處理
2.編譯階段:将預處理後的檔案進一步處理形成彙編檔案,包含彙編代碼,預處理後的檔案main.i -> main.asm(彙編檔案)
對代碼進行,語義分析、文法分析、詞法分析和優化
3.彙編階段:将彙編檔案按照彙編代碼一步步生成目标機器指令,從main.asm -> main.obj(目标機器檔案(二進制檔案))
4.連結階段:通過連結器将生成的目标機器檔案和庫檔案進行連結整合到一起,形成可執行檔案(.exe(二進制檔案))
1.編譯期:将源代碼交給編譯器,進行編譯生成可執行檔案的過程
2.運作期:将可執行檔案交給作業系統運作,直到程式運作結束的過程
通路修飾符和類的作用域屬于編譯期的概念
類的對象(執行個體化),以及指針引用等屬于運作期的概念
虛函數不能是私有的:因為多态是運作期多态,通路修飾符是編譯期存在的
三、宏
//AA.h
//----------------
#define AA 10
// \連接配接目前行和下一行的代碼,通常最後一行不加\,\後面不能加任何東西包括空格、tab、注釋
#define BB for(int i=0;i<10;i++){\
cout<<i<<endl;\
}
//宏可以加參數
#define CC(COUNT) for(int i=0;i<COUNT;i++){\
cout<<i<<endl;\
}
//宏隻是替換,不會做表達式計算求解
#define DD(A,B) A*B
//--------------------------
//main.cpp
cout<<AA<<endl;
BB
CC(5)
cout<<"---------------"<<endl;
int a=DD(2+3,4);
cout<<a<<endl;//輸出結果是14
“#”的一些特殊用法
#define AA(A) #A //“#”代表在兩邊加上""變成字元串
#define BB(B) #@B //相當于在變量兩邊加上單引号‘’,變成字元
#define CC() int a##b=10 //##是連接配接作用,a##b相當于ab
可以使用#undef取消宏的使用,限制宏的使用範圍
#undef AA
宏的優點:可以代替程式中常用的常量或者表達式,之後如果需要維護,隻需要維護一份就可以
宏的缺點:
1.不友善調試
2.難看出一些問題,可能出現安全問題
3.帶參數的宏不能進行表達式的計算
四、内聯函數
inline是内聯函數的關鍵字,編譯階段進行替換,可以提高函數的運作效率
對于一些簡單的函數來講,可能調用函數的時間比執行時間都長,可以使用内聯函數
缺點:如果程式中多次調用内聯函數會占用大量空間,相當于空間換時間的做法
inline int add(a,b)
{
return a+b;
}
适用于函數代碼量少,邏輯簡單的函數,對于一些含有for switch while dowhile 的不推薦使用
inline屬于建議性關鍵字,是否使用取決于編譯器的判斷,遞歸函數和虛函數一定不是内聯函數
不太重要的一點:在類内定義并初始化的預設為内聯函數,類内定義類外初始化的預設不是内聯函數