在C++實際開發中,難免會使用到一些你極為常用的算法(比如筆者經常使用的多線程技術),實現這些算法的類或是全局函數或是命名空間等等經常都要被使用多次,你會有哪些辦法來使用呢?筆者有4個辦法。
第一個方法就是你直接重新編寫一個和原來一樣的算法,但是這種方法又費時又費力,效率不高,只有初學者在沒有辦法的時候才會使用這種方法。第二種方法也是如此,就是復制一份代碼到新寫的文件中,這種方法的缺點是你不確定能否找到之前的代碼,而且一點也不像IT人員的解決方案。
我們重點介紹第三種和第四種方法。
第三種方法是在需要的地方聲明這個類或是全局函數。注意聲明的時候要使用extern關鍵字來聲明(任何東西都是如此:全局函數、類、結構……)比如下面的代碼:
#include <stdio.h>這個代碼在b.cpp中聲明了一個a.cpp文件中的函數並且使用了存儲類聲明符——extern。在這裡我先為大家介紹一下C++的存儲類。存儲類說明的是一個對象的存儲方法,通常有以下4種
1、extern 只聲明不定義,比如聲明一個變量卻不分配內存,一般用於兩個文件中的共享(a文件中定義了一個類,想要在b文件中訪問,則必須在b文件首部聲明一個extern的a文件中的類,上面示例使用的就是這種方法);
2、static 靜態,表示把這個東西定義在堆而不是棧裡。全局的對象一般都是靜態的,但是如果顯示聲明,則表示我發在其他文件中使用extern來調用它。如果在一個本應該定義在棧的代碼塊中聲明成static,也將聲明在堆中(比如全局函數);
3、register 注冊,把一個對象聲明到寄存器中,但是如果使用&操作符在程序中顯示地取地址,編譯器也將把這個對象定義到內存而不是寄存器中。使用register一般可以加快處理速度和減少內存使用量。
4、auto 默認、自動,聲明一個對象的默認形式,和static正好相反,不能把一個全局對象聲明成auto。
那麼,我們就明白了剛才那段代碼中我們使用extern是為什麼了。這種方法很常用,但是並不是最好的方法。
接下來,隆重介紹我們的第四種方法——頭文件!什麼?你說你沒有聽說過頭文件(head)?不可能,只要你寫的不是既不輸出也不輸入的console程序,也不是窗口中什麼也沒有的程序,那麼你就必須用到頭文件!看看你的C++編譯器中include目錄吧,那就是C++語言的標准頭文件庫,裡邊有C編寫控制台程序時常用的stdio還有C++新標准的iostream等等。沒錯,你猜對了,我們第四種方法就是編寫頭文件。哦哦哦,別把這個方法看的太難!其實就是把第三種方法變了變而已……但是的確方便得多。而且有一些封裝之類的思想。
好的,首先我們先來重新了解一下頭文件,如果你是高手,請讓你的思緒回到最開始編寫HelloWorld的時候。那麼,我首先要糾正一個問題——頭文件的定義。頭文件的定義不是“C++提供給程序員的類庫,是一些API之類的東西……”雲雲,而是“將一些類、全局函數、宏等資源集中聲明,並在在include後代替聲明,類似於類庫或叫做封裝。”當然,這不是官方的定義,是我根據個人理解而得出的。還有一個誤區——文件擴展名,很多windows新手都認為文件擴展名很重要,這其實是windows給我們的一個錯覺。因為windows總是以擴展名定義文件並說明文件使用哪種命令打開,但如果你使用過其他的操作系統就知道了,C++源文件並不需要必須是cpp,當然,頭文件也不需要都是h。都是文件,裡邊都存儲的是二進制代碼,編譯器也能編譯。比如C++標准的頭文件ios啦、cmath等等都沒有擴展名。
好了,所有需要的誤區也都說完了,我們來說第四種方法。首先看一個例程:
#include <iostream>
using namespace std;<<
你有什麼辦法讓編譯器不報錯呢?現在我們來編寫一個頭文件。
print();
沒錯,就一行,這就是一個頭文件,我們把它保存成c.h。然後把上面的a.cpp和main.cpp改一下。
#include <iostream> << #include
OK!你有沒有發現你成功了呢?而且,你可以編寫頭文件了!(如果你失敗了,聯系我的qq:2276768747,驗證全寫本文連接地址)
接下來,我來先講講include這個預編譯指令。什麼?#include嗎?我早學過了。是的,我先說的東西80%的人都知道,但是接著,我要說的80%的人不知道:#include我們一般使用兩種語法——1、#include <{編譯器系統include目錄下的文件}>;2、#include “{本目錄下或是編譯器include目錄的頭文件}” 注意到他們的不同了嗎?他們的不同是<>和””還有,第一種只在include目錄下尋找頭文件,而第二種在當前目錄和include目錄下尋找頭文件。這個功能使得引入自行編寫的頭文件成為可能(沒有也可以,可以放到include目錄下),所以我們可以將聲明甚至是定義放到頭文件裡面。還有一種情況,就是把聲明和定義全部放到頭文件裡面,這樣可以避免在使用模板和泛型的時候出現問題,請看下面的代碼:
#include <iostream> << #include
還有一些我要說:我們可以繼續模仿C++開發者——讓我們編寫的頭文件更“正式”(當然,不是給你講那成山的注釋是怎麼回事,更不是強逼迫你那麼做,我要講述一些頭文件中經常使用的預編譯指令)。首先我要給大家一個詳細的表格:
#空指令,無任何效果
#include包含一個源代碼文件
#define定義宏
#undef取消已定義的宏
#if如果給定條件為真,則編譯下面代碼
#ifdef如果宏已經定義,則編譯下面代碼
#ifndef如果宏沒有定義,則編譯下面代碼
#elif如果前面的#if給定條件不為真,當前條件為真,則編譯下面代碼
#endif結束一個#if……#else條件編譯塊
#error停止編譯並顯示錯誤信息
接下來,我一點點的解釋上面的宏定義指令,他可以讓你的頭文件具有判斷功能並且使你的頭文件變得更加正規和靈活。
首先,我們的老朋友#include,我們已經深入了解過了include的所有“底細”,在此不再贅述。
然後我們來看看#define。#define在C語言編程中很常用,一般用於定義一些具有特殊意義的全局函數或者常量,其正式名稱是“宏定義語句”,我們並不多講,只舉一個例子:
PI 3.14
接著看#undef,它是#define的逆運算,即消除宏定義:
PI 3.14 PI
#if是條件判斷語句,這個是判斷條件是否為真,為真執行#if到#endif之內的語句然後執行下方語句,否則直接執行下方語句,這個在頭文件中傳輸信息時用的比較多,重點講一下:
DEBUG 0 DEBUG
我最開始也不能理解,但是用得多了,就能夠很好地理解這個#if,其實它和我們C++的if語句一樣,下面會講到else……(實質上我也不知道會在哪裡用到,只是寫封裝的時候避免一些重復引用的問題雲雲)
接著說一下ifdef和ifndef,這裡注意:#ifdefined等價於#ifdef;#if!defined等價於#ifndef。也就是說ifdef的意思是判斷是否定義,如果定義了,就執行下面語句,否則不執行(else除外)而ifndef正好相反。話不多少看示例:
DEBUG printf( printf(
好了,我們終於可以講else了(我不希望你因為不耐煩和自以為掌握了封裝而不看下去,否則你將吃大虧的!你的頭文件總會出現重名、重復引用之類的東西,由於頭文件沒有main主函數,只能通過預處理來進行判斷條件等操作)。看看else,前面我就說了,預處理和C++語法一樣,所以這代表“否則”的意思。一行代碼+注釋遠遠大於100行解釋+說明(我的名言,記住了,先記住了,然後仔細看示例):
DEBUG printf( );
這個也很簡單吧!接下來,我們回憶一下我們用過的if……else if……這種語句格式。在判斷性預編譯機制中,我們也有這種類似的語句——#elif。不多說了,我們來看看示例代碼:
TWO printf( printf(
接著是這個:
#error指令將使編譯器顯示一條錯誤信息,然後停止編譯。
#line指令可以改變編譯器用來指出警告和錯誤信息的文件號和行號。
#pragma指令沒有正式的定義。編譯器可以自定義其用途。典型的用法是禁止或允許某些煩人的警告信息。
這個很簡單了,我就不再多說了,看網上的定義就可以了,這個error還挺常用的,仔細看一下,有興趣的網上搜搜也無妨。接著我淺談一下C++預處理機制對我們的封裝的作用:
1、由於我們封裝的頭文件沒有main方法,不能對於程序的執行的流程和引用文件等操作進行流程控制;
2、由於C++中頭文件會被自動inline,所以需要預處理一些引用以便避免重名和重復引用;
3、我們編寫頭文件封裝的時候難免會使用命名空間和類、結構之類的東西,所以我們一般需要控制生成和調用流程以便保證使用封裝時的安全。這裡多說一下:在if系列中的預處理語句中,除了可以放輸出,還可以放define甚至需要限定某些條件下會執行的語句,所以說,#if系列有的時候也被叫做“頭文件的if語句”。
希望大家掌握上述知識,靈活運用,以便使得將來的項目(過去的就算了,先別改了)更加穩定、靈活、高效。
在此特別聲明:本文中有關於預處理的例程和定義均來自http://www.kuqin.com/language/20090806/66164.html,但是為其添加了注釋並修改了格式,筆者為時間倉促沒有另行通知而梳表歉意,如原作者不希望筆者使用,請與我聯系:[email protected]。感謝各位,文章最後我將留下我的聯系方式。
QQ:2276768747 MSN:[email protected] email:[email protected] 感謝閱讀金雞獨立提供的計算機技術文章!再見!