無(wú)論是身處學(xué)校還是步入社會(huì),大家都嘗試過(guò)寫(xiě)作吧,借助寫(xiě)作也可以提高我們的語(yǔ)言組織能力,。大家想知道怎么樣才能寫(xiě)一篇比較優(yōu)質(zhì)的范文嗎?這里我整理了一些優(yōu)秀的范文,,希望對(duì)大家有所幫助,下面我們就來(lái)了解一下吧,。
標(biāo)準(zhǔn)命名空間 命名空間的概念及作用篇一
對(duì)于命名空間,,官方文檔已經(jīng)說(shuō)得很詳細(xì)[查看],,我在這里做了一下實(shí)踐和總結(jié),。
命名空間一個(gè)最明確的目的就是解決重名問(wèn)題,php中不允許兩個(gè)函數(shù)或者類(lèi)出現(xiàn)相同的名字,,否則會(huì)產(chǎn)生一個(gè)致命的錯(cuò)誤,。這種情況下只要避免命名重復(fù)就可以解決,最常見(jiàn)的一種做法是約定一個(gè)前綴,。例:項(xiàng)目中有兩個(gè)模塊:article和message board,,它們各自有一個(gè)處理用戶留言的類(lèi)comment。之后我可能想要增加對(duì)所有用戶留言的一些信息統(tǒng)計(jì)功能,,比如說(shuō)我想得到所有留言的數(shù)量,。這時(shí)候調(diào)用它們comment提供的方法是很好的做法,但是同時(shí)引入各自的comment類(lèi)顯然是不行的,,代碼會(huì)出錯(cuò),,在另一個(gè)地方重寫(xiě)任何一個(gè)comment也會(huì)降低維護(hù)性。那這時(shí)只能重構(gòu)類(lèi)名,,我約定了一個(gè)命名規(guī)則,,在類(lèi)名前面加上模塊名,像這樣:article_comment,、messageboard_comment 可以看到,,名字變得很長(zhǎng),那意味著以后使用comment的時(shí)候會(huì)寫(xiě)上更多的代碼(至少字符多了),。并且,,以后如果要對(duì)各個(gè)模塊增加更多的一些整合功能,或者是互相調(diào)用,,發(fā)生重名的時(shí)候就需要重構(gòu)名字,。當(dāng)然在項(xiàng)目開(kāi)始的時(shí)候就注意到這個(gè)問(wèn)題,并規(guī)定命名規(guī)則就能很好的避免這個(gè)問(wèn)題,。另一個(gè)解決方法可以考慮使用命名空間,。
注明:
本文提到的常量:php5.3開(kāi)始const關(guān)鍵字可以用在類(lèi)的外部。const和define都是用來(lái)聲明常量的(它們的區(qū)別不詳述),但是在命名空間里,,define的作用是全局的,,而const則作用于當(dāng)前空間。我在文中提到的常量是指使用const聲明的常量,。
基礎(chǔ)
命名空間將代碼劃分出不同的空間(區(qū)域),,每個(gè)空間的常量、函數(shù),、類(lèi)(為了偷懶,,我下邊都將它們稱(chēng)為元素)的名字互不影響,這個(gè)有點(diǎn)類(lèi)似我們常常提到的‘封裝'的概念,。創(chuàng)建一個(gè)命名空間需要使用namespace關(guān)鍵字,,這樣: 復(fù)制代碼代碼如下:
//創(chuàng)建一個(gè)名為'article'的命名空間 namespace article;?>
要注意的是,當(dāng)前腳本文件的第一個(gè)命名空間前面不能有任何代碼,,下面的寫(xiě)法都是錯(cuò)誤的: 復(fù)制代碼代碼如下: //例一
//在腳本前面寫(xiě)了一些邏輯代碼
//例二
//在腳本前面輸出了一些字符
為什么要說(shuō)第一個(gè)命名空間呢,?因?yàn)橥荒_本文件中可以創(chuàng)建多個(gè)命名空間。
下面我創(chuàng)建了兩個(gè)命名空間,,順便為這兩個(gè)空間各自添加了一個(gè)comment類(lèi)元素: 復(fù)制代碼代碼如下:
//創(chuàng)建一個(gè)名為'article'的命名空間 namespace article;//此comment屬于article空間的元素 class comment { }
//創(chuàng)建一個(gè)名為'messageboard'的命名空間 namespace messageboard;//此comment屬于messageboard空間的元素 class comment { } ?>
在不同空間之間不可以直接調(diào)用其它元素,,需要使用命名空間的語(yǔ)法: 復(fù)制代碼代碼如下:
namespace article;class comment { }
namespace messageboard;class comment { } //調(diào)用當(dāng)前空間(messageboard)的comment類(lèi) $comment = new comment();//調(diào)用article空間的comment類(lèi)
$article_comment = new articlecomment();?>
可以看到,在messageboard空間中調(diào)用article空間里的comment類(lèi)時(shí),,使用了一種像文件路徑的語(yǔ)法: 空間名元素名
除了類(lèi)之外,,對(duì)函數(shù)和常量的用法是一樣的,下面我為兩個(gè)空間創(chuàng)建了新的元素,,并在messageboard空間中輸出了它們的值,。復(fù)制代碼代碼如下:
namespace messageboard;const path = '/message_board';function getcommenttotal(){ return 300;} class comment { } //調(diào)用當(dāng)前空間的常量、函數(shù)和類(lèi) echo path;///message_board echo getcommenttotal();//300 $comment = new comment();//調(diào)用article空間的常量,、函數(shù)和類(lèi) echo articlepath;///article echo articlegetcommenttotal();//100 $article_comment = new articlecomment();?>
然后我的確得到了article空間的元素?cái)?shù)據(jù),。子空間
命名空間的調(diào)用語(yǔ)法像文件路徑一樣是有道理的,它允許我們自定義子空間來(lái)描述各個(gè)空間之間的關(guān)系,。抱歉我忘了說(shuō),,article和message board這兩個(gè)模塊其實(shí)都是處于同一個(gè)blog項(xiàng)目?jī)?nèi)。如果用命名空間來(lái)表達(dá)它們的關(guān)系,,是這樣: 復(fù)制代碼代碼如下:
//我用這樣的命名空間表示處于blog下的article模塊 namespace blogarticle;class comment { }
//我用這樣的命名空間表示處于blog下的message board模塊 namespace blogmessageboard;class comment { } //調(diào)用當(dāng)前空間的類(lèi)
$comment = new comment();//調(diào)用blogarticle空間的類(lèi)
$article_comment = new blogarticlecomment();?>
而且,,子空間還可以定義很多層次,比如說(shuō) blogarticlearchivesdate
公共空間
我有一個(gè)腳本文件,,里面有一些好用的函數(shù)和類(lèi): 復(fù)制代碼代碼如下:
function getip(){ } class filterxss { } ?>
在一個(gè)命名空間里引入這個(gè)腳本,,腳本里的元素不會(huì)歸屬到這個(gè)命名空間。如果這個(gè)腳本里沒(méi)有定義其它命名空間,,它的元素就始終處于公共空間中: 復(fù)制代碼代碼如下:
namespace blogarticle;//引入腳本文件
include './';$filter_xss = new filterxss();//出現(xiàn)致命錯(cuò)誤:找不到blogarticlefilterxss類(lèi) $filter_xss = new filterxss();//正確 ?>
調(diào)用公共空間的方式是直接在元素名稱(chēng)前加 就可以了,,否則php解析器會(huì)認(rèn)為我想調(diào)用當(dāng)前空間下的元素,。除了自定義的元素,還包括php自帶的元素,,都屬于公共空間,。
要提一下,其實(shí)公共空間的函數(shù)和常量不用加 也可以正常調(diào)用(不明白php為什么要這樣做),,但是為了正確區(qū)分元素,,還是建議調(diào)用函數(shù)的時(shí)候加上
名稱(chēng)術(shù)語(yǔ)
在說(shuō)別名和導(dǎo)入之前,需要知道關(guān)于空間三種名稱(chēng)的術(shù)語(yǔ),,以及php是怎樣解析它們的,。官方文檔說(shuō)得非常好,我就直接拿來(lái)套了,。
1.非限定名稱(chēng),,或不包含前綴的類(lèi)名稱(chēng),例如 $comment = new comment(),。如果當(dāng)前命名空間是blogarticle,,comment將被解析為blogarticlecomment。如果使用comment的代碼不包含在任何命名空間中的代碼(全局空間中),,則comment會(huì)被解析為comment。
2.限定名稱(chēng),,或包含前綴的名稱(chēng),,例如 $comment = new articlecomment()。如果當(dāng)前的命名空間是blog,,則comment會(huì)被解析為blogarticlecomment,。如果使用comment的代碼不包含在任何命名空間中的代碼(全局空間中),則comment會(huì)被解析為comment,。
3.完全限定名稱(chēng),,或包含了全局前綴操作符的名稱(chēng),例如 $comment = new articlecomment(),。在這種情況下,,comment總是被解析為代碼中的文字名(literal name)articlecomment。
其實(shí)可以把這三種名稱(chēng)類(lèi)比為文件名(例如 ),、相對(duì)路徑名(例如./article/),、絕對(duì)路徑名(例如 /blog/article/),這樣可能會(huì)更容易理解,。我用了幾個(gè)示例來(lái)表示它們: 復(fù)制代碼代碼如下:
//創(chuàng)建空間blog namespace blog;class comment { } //非限定名稱(chēng),,表示當(dāng)前blog空間 //這個(gè)調(diào)用將被解析成 blogcomment();$blog_comment = new comment();//限定名稱(chēng),表示相對(duì)于blog空間
//這個(gè)調(diào)用將被解析成 blogarticlecomment();$article_comment = new articlecomment();//類(lèi)前面沒(méi)有反斜桿 //完全限定名稱(chēng),,表示絕對(duì)于blog空間 //這個(gè)調(diào)用將被解析成 blogcomment();$article_comment = new blogcomment();//類(lèi)前面有反斜桿 //完全限定名稱(chēng),,表示絕對(duì)于blog空間
//這個(gè)調(diào)用將被解析成 blogarticlecomment();$article_comment = new blogarticlecomment();//類(lèi)前面有反斜桿
//創(chuàng)建blog的子空間article namespace blogarticle;class comment { } ?>
其實(shí)之前我就一直在使用非限定名稱(chēng)和完全限定名稱(chēng),現(xiàn)在它們終于可以叫出它們的名稱(chēng)了。
別名和導(dǎo)入
別名和導(dǎo)入可以看作是調(diào)用命名空間元素的一種快捷方式,。php并不支持導(dǎo)入函數(shù)或常量,。它們都是通過(guò)使用use操作符來(lái)實(shí)現(xiàn): 復(fù)制代碼代碼如下:
namespace blogarticle;class comment { }
//創(chuàng)建一個(gè)bbs空間(我有打算開(kāi)個(gè)論壇)namespace bbs;//導(dǎo)入一個(gè)命名空間 use blogarticle;//導(dǎo)入命名空間后可使用限定名稱(chēng)調(diào)用元素 $article_comment = new articlecomment();//為命名空間使用別名 use blogarticle as arte;//使用別名代替空間名
$article_comment = new artecomment();//導(dǎo)入一個(gè)類(lèi)
use blogarticlecomment;//導(dǎo)入類(lèi)后可使用非限定名稱(chēng)調(diào)用元素 $article_comment = new comment();//為類(lèi)使用別名
use blogarticlecomment as comt;//使用別名代替空間名
$article_comment = new comt();?>
我注意到,如果導(dǎo)入元素的時(shí)候,,當(dāng)前空間有相同的名字元素將會(huì)怎樣,?顯然結(jié)果會(huì)發(fā)生致命錯(cuò)誤。
例:
復(fù)制代碼代碼如下:
namespace blogarticle;class comment { }
namespace bbs;class comment { } class comt { }
//導(dǎo)入一個(gè)類(lèi)
use blogarticlecomment;$article_comment = new comment();//與當(dāng)前空間的comment發(fā)生沖突,,程序產(chǎn)生致命錯(cuò)誤 //為類(lèi)使用別名
use blogarticlecomment as comt;$article_comment = new comt();//與當(dāng)前空間的comt發(fā)生沖突,,程序產(chǎn)生致命錯(cuò)誤 ?> 動(dòng)態(tài)調(diào)用
php提供了namespace關(guān)鍵字和__namespace__魔法常量動(dòng)態(tài)的訪問(wèn)元素,__namespace__可以通過(guò)組合字符串的形式來(lái)動(dòng)態(tài)訪問(wèn): 復(fù)制代碼代碼如下:
namespace blogarticle;const path = '/blog/article';class comment { }
//namespace關(guān)鍵字表示當(dāng)前空間 echo namespacepath;///blog/article $comment = new namespacecomment();//魔法常量__namespace__的值是當(dāng)前空間名稱(chēng) echo __namespace__;//blogarticle //可以組合成字符串并調(diào)用
$comment_class_name = __namespace__.'comment';$comment = new $comment_class_name();?>
字符串形式調(diào)用問(wèn)題
上面的動(dòng)態(tài)調(diào)用的例子中,,我們看到了字符串形式的動(dòng)態(tài)調(diào)用方式,,如果要使用這種方式要注意兩個(gè)問(wèn)題。
1.使用雙引號(hào)的時(shí)候特殊字符可能被轉(zhuǎn)義 復(fù)制代碼代碼如下:
namespace blogarticle;class name { } //我是想調(diào)用blogarticlename $class_name = __namespace__.“name”;//但是n將被轉(zhuǎn)義為換行符 $name = new $class_name();//發(fā)生致命錯(cuò)誤 ?>
2.不會(huì)認(rèn)為是限定名稱(chēng)
php在編譯腳本的時(shí)候就確定了元素所在的空間,,以及導(dǎo)入的情況,。而在解析腳本時(shí)字符串形式調(diào)用只能認(rèn)為是非限定名稱(chēng)和完全限定名稱(chēng),而永遠(yuǎn)不可能是限定名稱(chēng),。復(fù)制代碼代碼如下:
namespace blog;//導(dǎo)入common類(lèi)
use blogarticlecommon;//我想使用非限定名稱(chēng)調(diào)用blogarticlecommon $common_class_name = 'common';//實(shí)際會(huì)被當(dāng)作非限定名稱(chēng),,也就表示當(dāng)前空間的common類(lèi),但我當(dāng)前類(lèi)沒(méi)有創(chuàng)建common類(lèi) $common = new $common_class_name();//發(fā)生致命錯(cuò)誤:common類(lèi)不存在 //我想使用限定名稱(chēng)調(diào)用blogarticlecommon $common_class_name = 'articlecommon';//實(shí)際會(huì)被當(dāng)作完全限定名稱(chēng),,也就表示article空間下的common類(lèi),,但我下面只定義了blogarticle空間而不是article空間
$common = new $common_class_name();//發(fā)生致命錯(cuò)誤:articlecommon類(lèi)不存在
namespace blogarticle;class common { } ?> 總結(jié)
我對(duì)php的命名空間剛剛接觸,也不能隨便給一些沒(méi)有實(shí)踐的建議,。我個(gè)人認(rèn)為命名空間的作用和功能都很強(qiáng)大,,如果要寫(xiě)插件或者通用庫(kù)的時(shí)候再也不用擔(dān)心重名問(wèn)題。不過(guò)如果項(xiàng)目進(jìn)行到一定程度,,要通過(guò)增加命名空間去解決重名問(wèn)題,,我覺(jué)得工作量不會(huì)比重構(gòu)名字少。也不得不承認(rèn)它的語(yǔ)法會(huì)對(duì)項(xiàng)目增加一定的復(fù)雜度,,因此從項(xiàng)目一開(kāi)始的時(shí)候就應(yīng)該很好的規(guī)劃它,,并制定一個(gè)命名規(guī)范。
標(biāo)準(zhǔn)命名空間 命名空間的概念及作用篇二
進(jìn)行對(duì)象的序列化,,的引用,,ization命名空間。這樣就可以在文件中使用序列化所需要的各種特性了,。
imports ization
如果對(duì)xml serialization缺少了解,,請(qǐng)首先參考拙文:中實(shí)現(xiàn)對(duì)象序列化
2005-04-05
對(duì)象序列化
上面的例子包含了典型的xml中常見(jiàn)的各種元素:xml聲明、xml根節(jié)點(diǎn),、xml節(jié)點(diǎn),、xml屬性,、xml集合。除xml聲明外,,中都有對(duì)應(yīng)的特性用于定義這些元素,。這些特性包括:xmlrootattribute、xmltypeattribute,、xmlelementattribute,、xmlattributeattribute、xmlarrayattribute和xmlarrayitemattribute,。另外,,還有兩個(gè)常用的特性,xmlignoreattribute用于標(biāo)記在對(duì)象序列化時(shí)需要被忽略的部分,,xmlincludeattribute用于標(biāo)記在生成xml schema時(shí)需要包括的類(lèi)型,。如果沒(méi)有顯式地標(biāo)記任何特性,那么默認(rèn)類(lèi)的特性為xmltypeattribute,、類(lèi)成員的特性為xmlelementattribute,,且名稱(chēng)為類(lèi)或類(lèi)成員的名稱(chēng)。例如:
public class order
public id as string
public orderdate as string
end class
如果不做任何特性標(biāo)記,,使用下面的代碼序列化時(shí): dim o as new order
with o
.id = 123456
.orderdate = tdatestring
end with
dim writer as new xmltextwriter(“”, 8)
dim serializer as new xmlserializer(gettype(order))
ting = ed ize(writer, o)
序列化后的xml為:
123456
2005-4-11
可以看到,,對(duì)應(yīng)order類(lèi),,而
和
分別對(duì)應(yīng)order類(lèi)中的字段id和orderdate。另外,,多了一個(gè)xml聲明和兩個(gè)xml命名空間,。
自動(dòng)添加的,但是encoding是在xmltextwriter中指定的,如果不指定encoding,,那么xml聲明只有,。 1.1,這個(gè)版本中只支持xml 1.0版本,。另外,如果不指定encoding,那么默認(rèn)的編碼可能也是utf8(沒(méi)找到相關(guān)的資料),。
.net默認(rèn)為order類(lèi)添加了xmlschema和xmlschema-instance兩個(gè)w3c的命名空間。該命名空間也可以自己指定,,方法是使用xmlserializer的另一個(gè)serialize方法,。
dim ns as new xmlserializernamespaces (“", ”“)ting = ed ize(writer, o, ns)
要將類(lèi)序列化為xml節(jié)點(diǎn):
_
public class order‘ any code class
要將類(lèi)序列化為xml根節(jié)點(diǎn):
_
public class order‘ any code class
當(dāng)在類(lèi)中同時(shí)使用xmlrootattribute,、xmltypeattribute時(shí),序列化文檔中的類(lèi)型以xmlrootattribute為準(zhǔn):
_
public class order‘ any code class
要將類(lèi)成員序列化為xml節(jié)點(diǎn):
_
public id as string要將類(lèi)成員序列化為xml屬性:
_
public id as string要將類(lèi)成員序列化為xml集合:
_
public class order_
public id as stringpublic orderdate as string
_
public items as new arraylistend class
_
public class orderitempublic name as string
end class
使用特性的一個(gè)好處是:可以在代碼和序列化的文檔中使用不同的編碼規(guī)范,。
標(biāo)準(zhǔn)命名空間 命名空間的概念及作用篇三
基本技能 12.5:命名空間
我們?cè)?jīng)在第一章中對(duì)命名空間進(jìn)行簡(jiǎn)單的介紹,。這里我們將對(duì)命名空間進(jìn)行深入的討論。使用命名空間的目的是對(duì)標(biāo)識(shí)符的名稱(chēng)進(jìn)行本地化,,以避免命名沖突,。在c++中,變量,、函數(shù)和類(lèi)都是大量存在的,。如果沒(méi)有命名空間,這些變量,、函數(shù),、類(lèi)的名稱(chēng)將都存在于全局命名空間中,會(huì)導(dǎo)致很多沖突,。比如,,如果我們?cè)谧约旱某绦蛑卸x了一個(gè)函數(shù)toupper(),這將重寫(xiě)標(biāo)準(zhǔn)庫(kù)中的toupper()函數(shù),,這是因?yàn)檫@兩個(gè)函數(shù)都是位于全局命名空間中的,。命名沖突還會(huì)發(fā)生在一個(gè)程序中使用兩個(gè)或者更多的第三方庫(kù)的情況中。此時(shí),,很有可能,,其中一個(gè)庫(kù)中的名稱(chēng)和另外一個(gè)庫(kù)中的名稱(chēng)是相同的,這樣就沖突了,。這種情況會(huì)經(jīng)常發(fā)生在類(lèi)的名稱(chēng)上,。比如,我們?cè)谧约旱某绦蛑卸x了一個(gè)stack類(lèi),,而我們程序中使用的某個(gè)庫(kù)中也可能定義了一個(gè)同名的類(lèi),,此時(shí)名稱(chēng)就沖突了。
namespace關(guān)鍵字的出現(xiàn)就是針對(duì)這種問(wèn)題的,。由于這種機(jī)制對(duì)于聲明于其中的名稱(chēng)都進(jìn)行了本地化,就使得相同的名稱(chēng)可以在不同的上下文中使用,,而不會(huì)引起名稱(chēng)的沖突,?;蛟S命名空間最大的受益者就是c++中的標(biāo)準(zhǔn)庫(kù)了。在命名空間出現(xiàn)之前,,整個(gè)c++庫(kù)都是定義在全局命名空間中的(這當(dāng)然也是唯一的命名空間)。引入命名空間后,,c++庫(kù)就被定義到自己的名稱(chēng)空間中了,稱(chēng)之為std,。這樣就減少了名稱(chēng)沖突的可能性。我們也可以在自己的程序中創(chuàng)建自己的命名空間,,這樣可以對(duì)我們認(rèn)為可能導(dǎo)致沖突的名稱(chēng)進(jìn)行本地化,。這點(diǎn)在我們創(chuàng)建類(lèi)或者是函數(shù)庫(kù)的時(shí)候是特別重要的,。命名空間基礎(chǔ)
namespace關(guān)鍵字使得我們可以通過(guò)創(chuàng)建作用范圍來(lái)對(duì)全局命名空間進(jìn)行分隔,。本質(zhì)上來(lái)講,,一個(gè)命名空間就定義了一個(gè)范圍,。定義命名空間的基本形式如下:
namespace 名稱(chēng){//聲明}
在命名空間中定義的任何東西都局限于該命名空間內(nèi),。
下面就是一個(gè)命名空間的例子,,其中對(duì)一個(gè)實(shí)現(xiàn)簡(jiǎn)單遞減計(jì)數(shù)器的類(lèi)進(jìn)行了本地化,。在該命名空間中定義了計(jì)數(shù)器類(lèi)用來(lái)實(shí)現(xiàn)計(jì)數(shù),;其中的upperbound和lowerbound用來(lái)表示計(jì)數(shù)器的上界和下界,。//演示命名空間
namespace counternamespace {
int upperbound;
int lowerbound;
class counter {
int count;
public:
counter(int n){
if(n <= upperbound){
count = n;}
else {
count = upperbound;} }
void reset(int n){
if(n < upperbound){
count = n;} }
int run(){
if(count > lowerbound){
return count--;}
else
{
return lowerbound;
}
} };}
其中的upperbound,lowerbound和類(lèi)counter都是有命名空間counternamespace定義范圍的組成部分,。
在命名空間中聲明的標(biāo)識(shí)符是可以被直接引用的,,不需要任何的命名空間的修飾符。例如,,在counternamesapce命名空間中,run()函數(shù)中就可以直接在語(yǔ)句中引用lowerbound:
if(count > lowerbound){
return count--;}
然而,,既然命名空間定義了一個(gè)范圍,那么我們?cè)诿臻g之外就需要使用范圍解析運(yùn)算符來(lái)引用命名空間中的對(duì)象,。例如,在命名空間counternamespace定義的范圍之外給upperbound賦值為10,,就必須這樣寫(xiě):
counternamespace::upperbound = 10;或者在counternamespace定義的范圍之外想要聲明一個(gè)counter類(lèi)的對(duì)象就必須這樣寫(xiě):
counternamespace::counter obj;
一般來(lái)講,,在命名空間之外想要訪問(wèn)命名空間內(nèi)部的成員需要在成員前面加上命名空間和范圍解析運(yùn)算符。
下面的程序演示了如何使用counternamespace這個(gè)命名空間: //演示命名空間
#include
using namespace std;
namespace counternamespace {int upperbound;
int lowerbound;
class counter {
int count;
public:
counter(int n){
if(n <= upperbound){
count = n;}
else {
count = upperbound;} }
void reset(int n){
if(n < upperbound){
count = n;} }
int run(){
if(count > lowerbound){
return count--;} else
return lowerbound;} };}
int main(){
counternamespace::upperbound = 100;
counternamespace::lowerbound = 0;
counternamespace::counter ob1(10);
int i;
do {
i = ();
cout << i << “ ”;
} while(i > counternamespace::lowerbound);
cout << endl;
counternamespace::counter ob2(20);
do {
i = ();
cout << i << “ ”;
} while(i > counternamespace::lowerbound);
cout << endl;
(100);
do {
i = ();
cout << i << “ ”;
} while(i > counternamespace::lowerbound);
cout << endl;
return 0;}
請(qǐng)注意:counter類(lèi)以及upperbound和lowerbound的引用都是在前面加上了counternamespace修飾符,。但是,,一旦聲明了counter類(lèi)型的對(duì)象,,就沒(méi)有必須在對(duì)該對(duì)象的任何成員使用這種修飾符了。()是可以被直接調(diào)用的,。其中的命名空間是可以被解析的。
相同的空間名稱(chēng)是可以被多次聲明的,這種聲明向相互補(bǔ)充的,。這就使得命名空間可以被分割到幾個(gè)文件中甚至是同一個(gè)文件的不同地方中,。例如:
namespace ns {
int i;}
//...namespace ns {
int j;}
其中命名空間ns被分割成兩部分,,但是兩部分的內(nèi)容卻是位于同一命名空間中的,。也就是ns。最后一點(diǎn):命名空間是可以嵌套的,。也就是說(shuō)可以在一個(gè)命名空間內(nèi)部聲明另外的命名空間,。using關(guān)鍵字
如果在程序中需要多次引用某個(gè)命名空間的成員,那么按照之前的說(shuō)法,,我們每次都要使用范圍解析符來(lái)指定該命名空間,這是一件很麻煩的事情,。為了解決這個(gè)問(wèn)題,人們引入了using關(guān)鍵字,。using語(yǔ)句通常有兩種使用方式:
using namespace 命名空間名稱(chēng);using 命名空間名稱(chēng)::成員,;
第一種形式中的命名空間名稱(chēng)就是我們要訪問(wèn)的命名空間,。該命名空間中的所有成員都會(huì)被引入到當(dāng)前范圍中,。也就是說(shuō),,他們都變成當(dāng)前命名空間的一部分了,使用的時(shí)候不再需要使用范圍限定符了,。第二種形式只是讓指定的命名空間中的指定成員在當(dāng)前范圍中變?yōu)榭梢?jiàn)。我們用前面的counternamespace來(lái)舉例,,下面的using語(yǔ)句和賦值語(yǔ)句都是有效的:
using counternamespace::lowerbound;//只有l(wèi)owerbound當(dāng)前是可見(jiàn)的 lowerbound = 10;//這樣寫(xiě)是合法的,因?yàn)閘owerbound成員當(dāng)前是可見(jiàn)的 using counternamespace;//所有counternamespace空間的成員當(dāng)前都是可見(jiàn)的
upperbound = 100;//這樣寫(xiě)是合法的,,因?yàn)樗械腸ounternamespace成員目前都是可見(jiàn)的
下面是我們對(duì)之前的程序進(jìn)行修改的結(jié)果: //使用using
#include
using namespace std;namespace counternamespace { int upperbound;
int lowerbound;
class counter {
int count;
public:
counter(int n){
if(n < upperbound){
count = n;}
else {
count = upperbound;} }
void reset(int n){
if(n <= upperbound){
count = n;} }
int run(){
if(count > lowerbound){
return count--;}
else {
return lowerbound;} } };}
int main(){
//這里只是用counternamespace中的upperbound using counternamespace::upperbound;
//此時(shí)對(duì)upperbound的訪問(wèn)就不需要使用范圍限定符了 upperbound = 100;
//但是使用lowerbound的時(shí)候,還是需要使用范圍限定符的 counternamespace::lowerbound = 0;counternamespace::counter ob1(10);
int i;
do {
i = ();cout << i << “ ”;
}while(i > counternamespace::lowerbound);cout << endl;
//下面我們將使用整個(gè)counternamespace的命名空間
using namespace counternamespace;counter ob2(20);
do {
i = ();cout << i << “ ”;
}while(i > counternamespace::lowerbound);cout << endl;
(100);lowerbound = 90;
do {
i = ();cout << i << “ ”;}while(i > lowerbound);
return 0;}
上面的程序還為我們演示了重要的一點(diǎn):當(dāng)我們用using引入一個(gè)命名空間的時(shí)候,,如果之前有引用過(guò)別的命名空間(或者同一個(gè)命名空間),,則不會(huì)覆蓋掉對(duì)之前的引入,,而是對(duì)之前引入內(nèi)容的補(bǔ)充,。也就是說(shuō),到最后,,上述程序中的std和counternamespace這兩個(gè)命名空間都變成全局空間了,。沒(méi)有名稱(chēng)的命名空間
有一種特殊的命名空間,,叫做未命名的命名空間,。這種沒(méi)有名稱(chēng)的命名空間使得我們可以創(chuàng)建在一個(gè)文件范圍里可用的命名空間。其一般形式如下: namespace {
//聲明 }
我們可以使用這種沒(méi)有名稱(chēng)的命名空間創(chuàng)建只有在聲明他的文件中才可見(jiàn)的標(biāo)識(shí)符,。也即是說(shuō),,只有在聲明這個(gè)命名空間的文件中,它的成員才是可見(jiàn)的,,它的成員才是可以被直接使用的,,不需要命名空間名稱(chēng)來(lái)修飾,。對(duì)于其他文件,,該命名空間是不可見(jiàn)的,。我們?cè)谇懊嬖?jīng)提到過(guò),把全局名稱(chēng)的作用域限制在聲明他的文件的一種方式就是把它聲明為靜態(tài)的,。盡管c++是支持靜態(tài)全局聲明的,,但是更好的方式就是使用這里的未命名的命名空間。std命名空間
標(biāo)準(zhǔn)c++把自己的整個(gè)庫(kù)定義在std命名空間中,。這就是本書(shū)的大部分程序都有下面代碼的原因:
using namespace std;
這樣寫(xiě)是為了把std命名空間的成員都引入到當(dāng)前的命名空間中,以便我們可以直接使用其中的函數(shù)和類(lèi),,而不用每次都寫(xiě)上std::。
當(dāng)然,,我們是可以顯示地在每次使用其中成員的時(shí)候都指定std::,只要我們喜歡,。例如,我們可以顯示地采用如下語(yǔ)句指定cout:
std::cout << “顯示使用std::來(lái)指定cout”;
如果我們的程序中只是少量地使用了std命名空間中的成員,,或者是引入std命名空間可能導(dǎo)致命名空間的沖突的話,,我們就沒(méi)有必要使用using namespace std;了,。然而,如果在程序中我們要多次使用std命名空間的成員,,則采用using namespace std;的方式把std命名空間的成員都引入到當(dāng)前命名空間中會(huì)顯得方便很多,,而不用每次都單獨(dú)在使用的時(shí)候顯示指定,。
標(biāo)準(zhǔn)命名空間 命名空間的概念及作用篇四
c++命名空間namespace 雖然使用命名空間的方法,有多種可供選擇,。但是不能貪圖方便,一味使用using 指令,,這樣就完全背離了設(shè)計(jì)命名空間的初衷,也失去了命名空間應(yīng)該具有的防止名稱(chēng)沖突的功能,。
一般情況下,對(duì)偶爾使用的命名空間成員,,應(yīng)該使用命名空間的作用域解析運(yùn)算符來(lái)直接給名稱(chēng)定位。而對(duì)一個(gè)大命名空間中的經(jīng)常要使用的少數(shù)幾個(gè)成員,,提倡使用using聲明,而不應(yīng)該使用using編譯指令,。只有需要反復(fù)使用同一個(gè)命名空間的許多數(shù)成員時(shí),使用using編譯指令,,才被認(rèn)為是可取的,。
例如,,如果一個(gè)程序()只使用一兩次cout,而且也不使用std命名空間中的其他成員,,則可以使用命名空間的作用域解析運(yùn)算符來(lái)直接定位,。如: #include
……
std::cout << “hello, world!” << std::endl;std::cout << “outer::i = ” << outer::i << “, inner::i = ” << outer::inner::i << std::endl;又例如,如果一個(gè)程序要反復(fù)使用std命名空間中的cin,、cout和cerr(),,而不怎么使用其他std命名空間中的其他成員,,則應(yīng)該使用using 聲明而不是using指令,。如:
#include
……
using std::cout;cout << “hello, world!” << endl;cout << “outer::i = ” << outer::i << “, inner::i = ” << outer::inner::i << endl;4)命名空間的名稱(chēng)l
命名空間別名 標(biāo)準(zhǔn)c++引入命名空間,,主要是為了避免成員的名稱(chēng)沖突,。若果用戶都給自己的命名空間取簡(jiǎn)短的名稱(chēng),那么這些(往往同是全局級(jí)的)命名空間本身,也可能發(fā)生名稱(chēng)沖突,。如果為了避免沖突,而為命名空間取很長(zhǎng)的名稱(chēng),,則使用起來(lái)就會(huì)不方便,。這是一個(gè)典型的兩難問(wèn)題,。
標(biāo)準(zhǔn)c++為此提供了一種解決方案——命名空間別名,,格式為: namespace 別名 = 命名空間名;例如:(at&t美國(guó)電話電報(bào)公司)
namespace american_telephone_and_telegraph { // 命名空間名太長(zhǎng)
class string {
string(const char*);
// ……
} }
american_telephone_and_telegraph::string s1 // 使用不方便
= new american_telephone_and_telegraph::string(“grieg”);
namespace att = american_telephone_and_telegraph;// 定義別名
att::string s2 = new att::string(“bush”);// 使用方便 att::string s3 = new att::string(“nielsen”);
l
無(wú)名命名空間 標(biāo)準(zhǔn)c++引入命名空間,,除了可以避免成員的名稱(chēng)發(fā)生沖突之外,,還可以使代碼保持局部性,從而保護(hù)代碼不被他人非法使用,。如果你的目的主要是后者,,而且又為替命名空間取一個(gè)好聽(tīng),、有意義,、且與別人的命名空間不重名的名稱(chēng)而煩惱的話,標(biāo)準(zhǔn)c++還允許你定義一個(gè)無(wú)名命名空間,。你可以在當(dāng)前編譯單元中(無(wú)名命名空間之外),,直接使用無(wú)名命名空間中的成員名稱(chēng),,但是在當(dāng)前編譯單元之外,,它又是不可見(jiàn)的。無(wú)名命名空間的定義格式為: namespace {
聲明序列可選 } 實(shí)際上,,上面的定義等價(jià)于:(標(biāo)準(zhǔn)c++中有一個(gè)隱含的使用指令)
namespace $$$ {
聲明序列可選 } using namespace $$$;例如: namespace {
int i;
void f(){/*……*/} } int main(){
i = 0;// 可直接使用無(wú)名命名空間中的成員i
f();// 可直接使用無(wú)名命名空間中的成員f()}
標(biāo)準(zhǔn)命名空間 命名空間的概念及作用篇五
本講基本要求
* 掌握:命名空間的作用及定義,;如何使用命名空間,。
* 了解:使用早期的函數(shù)庫(kù)
重點(diǎn),、難點(diǎn)
◆命名空間的作用及定義,;如何使用命名空間,。
在學(xué)習(xí)本書(shū)前面各章時(shí),讀者已經(jīng)多次看到在程序中用了以下語(yǔ)句: using namespace std,;
這就是使用了命名空間std。在本講中將對(duì)它作較詳細(xì)的介紹,。
一、為什么需要命名空間(問(wèn)題提出)
命名空間是ansic++引入的可以由用戶命名的作用域,,用來(lái)處理程序中常見(jiàn)的同名沖突。
在c語(yǔ)言中定義了3個(gè)層次的作用域,,即文件(編譯單元)、函數(shù)和復(fù)合語(yǔ)句,。c++又引入了類(lèi)作用域,類(lèi)是出現(xiàn)在文件內(nèi)的。在不同的作用域中可以定義相同名字的變量,,互不于擾,系統(tǒng)能夠區(qū)別它們,。
1、全局變量的作用域是整個(gè)程序,,在同一作用域中不應(yīng)有兩個(gè)或多個(gè)同名的實(shí)體(enuty),,包括變量,、函數(shù)和類(lèi)等,。
例:如果在文件中定義了兩個(gè)類(lèi),,在這兩個(gè)類(lèi)中可以有同名的函數(shù)。在引用時(shí),,為了區(qū)別,,應(yīng)該加上類(lèi)名作為限定: class a //聲明a類(lèi)
{ public:
void funl();//聲明a類(lèi)中的funl函數(shù)
private:
int i,; },;
void a::funl()//定義a類(lèi)中的funl函數(shù)
{????}
class b //聲明b類(lèi)
{ public:
void funl(),; //b類(lèi)中也有funl函數(shù)
void fun2(),; },;
void b::funl()//定義b類(lèi)中的funl函數(shù)
{ ????} 這樣不會(huì)發(fā)生混淆,。
在文件中可以定義全局變量(global variable),它的作用域是整個(gè)程序,。如果在文件a中定義了一個(gè)變量a int a=3;
在文件b中可以再定義一個(gè)變量a int a=5;在分別對(duì)文件a和文件b進(jìn)行編譯時(shí)不會(huì)有問(wèn)題,。但是,,如果一個(gè)程序包括文件a和文件b,那么在進(jìn)行連接時(shí),,會(huì)報(bào)告出錯(cuò),因?yàn)樵谕粋€(gè)程序中有兩個(gè)同名的變量,,認(rèn)為是對(duì)變量的重復(fù)定義,。
可以通過(guò)extern聲明同一程序中的兩個(gè)文件中的同名變量是同一個(gè)變量。如果在文件b中有以下聲明: extem int a,;
表示文件b中的變量a是在其他文件中已定義的變量,。由于有此聲明,在程序編譯和連接后,,文件a的變量a的作用域擴(kuò)展到了文件b。如果在文件b中不再對(duì)a賦值,,則在文件b中用以下語(yǔ)句輸出的是文件a中變量a的值: cout<
2,、程序中就會(huì)出現(xiàn)名字沖突。
在簡(jiǎn)單的程序設(shè)計(jì)中,,只要人們小心注意,可以爭(zhēng)取不發(fā)生錯(cuò)誤,。但是,,一個(gè)大型的應(yīng)用軟件,往往不是由一個(gè)人獨(dú)立完成的,,而是由若干人合作完成的,不同的人分別完成不同的部分,,最后組合成一個(gè)完整的程序,。假如不同的人分別定義了類(lèi),放在不同的頭文件中,,在主文件(包含主函數(shù)的文件)需要用這些類(lèi)時(shí),,就用#include命令行將這些頭文件包含進(jìn)來(lái),。由于各頭文件是由不同的人設(shè)計(jì)的,有可能在不同的頭文件中用了相同的名字來(lái)命名所定義的類(lèi)或函數(shù),。例4 名字沖突
程序員甲在頭文件headerl.h中定義了類(lèi)student和函數(shù)fun,。//例4中的頭文件header1(頭文件1,,沒(méi)其文件名為cc8-4-h1.h)#include
#include
using namespace std;class student //聲明student類(lèi)
{ public: student(int n,string nam,int a){ num=n;name=nam;age=a;} void get_data();private: int num;string name;int age;};void student::get_data()//成員函數(shù)定義 { cout<wang 18 2.82843 如果程序員乙寫(xiě)了頭文件header2.h,,在其中除了定義其他類(lèi)以外,還定義了類(lèi)student和函數(shù)fun,,但其內(nèi)容與頭文件headerl.h中的student和函數(shù)fun有所不同。//例4中的頭文件header2 #include
#include
using namespace std;class student //聲明student類(lèi) { public: student(int n,string nam,char s)//參數(shù)與headerl中的student不同
{ num=n;name=nam;sex=s;} void get_data();private: int num;string name;char sex;};//此項(xiàng)與headerl不同void student::get_data()//成員函數(shù)定義 { cout<
double fun(double a,double b)//定義全局函數(shù)
{ return sqrt(a-b);} //返回值與headerl中的fun函數(shù)不同 //頭文件2中可能還有其他內(nèi)容
假如主程序員在其程序中要用到headerl.h中的student和函數(shù)fun,,因而在程序中包含了頭文件headerl.h,同時(shí)要用到頭文件header2.h中的一些內(nèi)容(但對(duì)header2.h中包含與headerl.h中的student類(lèi)和fun函數(shù)同名而內(nèi)容不同的類(lèi)和函數(shù)并不知情,,因?yàn)樵谝粋€(gè)頭文件中往往包含許多不同的信息,而使用者往往只關(guān)心自己所需要的部分,,而不注意其他內(nèi)容),因而在程序中又包含了頭文件header2.h,。如果主文件(包含主函數(shù)的文件)如下: #include
using namespace std;#include ”header1.h“//包含頭文件l #include ”header2.h“//包含頭文件2 int main(){ student stud1(101,”wang“,18);_data();cout<
3、全局命名空間污染(global namespace pollution),。
在程序中還往往需要引用一些庫(kù)(包括c++編譯系統(tǒng)提供的庫(kù),、由軟件開(kāi)發(fā)商提供的庫(kù)或者用戶自己開(kāi)發(fā)的庫(kù)),為此需要包含有關(guān)的頭文件,。如果在這些庫(kù)中包含有與程序的全局實(shí)體同名的實(shí)體,,或者不同的庫(kù)中有相同的實(shí)體名,則在編譯時(shí)就會(huì)出現(xiàn)名字沖突,。
為了避免這類(lèi)問(wèn)題的出現(xiàn),,人們提出了許多方法,,例如:將實(shí)體的名字寫(xiě)得長(zhǎng)—些(包含十幾個(gè)或幾十個(gè)字母和字符),;把名字起得特殊一些,,包括一些特殊的字符;由編譯系統(tǒng)提供的內(nèi)部全局標(biāo)識(shí)符都用下劃線作為前綴,,如_complex(),以避免與用戶命名的實(shí)體同名,;由軟件開(kāi)發(fā)商提供的實(shí)體的名字用特定的字符作為前綴。但是這樣的效果并不理想,,而且增加了閱讀程序的難度,,可讀性降低了。c語(yǔ)言和早期的c++語(yǔ)言沒(méi)有提供有效的機(jī)制來(lái)解決這個(gè)問(wèn)題,,沒(méi)有使庫(kù)的提供者能夠建立自己的命名空間的工具,。人們希望ansi c++標(biāo)準(zhǔn)能夠解決這個(gè)問(wèn)題,提供—種機(jī)制,、一種工具,使由庫(kù)的設(shè)計(jì)者命名的全局標(biāo)識(shí)符能夠和程序的全局實(shí)體名以及其他庫(kù)的全局標(biāo)識(shí)符區(qū)別開(kāi)來(lái),。
二,、什么是命名空間(解決方案)
命名空間:實(shí)際上就是一個(gè)由程序設(shè)計(jì)者命名的內(nèi)存區(qū)域,程序設(shè)計(jì)者可以根據(jù)需要指定一些有名字的空間域,,把一些全局實(shí)體分別放在各個(gè)命名空間中,,從而與其他全局實(shí)體分隔開(kāi)來(lái)。
如: namespace ns1 //指定命名中間nsl
{ int a,;
double b;} namespace是定義命名空間所必須寫(xiě)的關(guān)鍵字,nsl是用戶自己指定的命名空間的名字(可以用任意的合法標(biāo)識(shí)符,這里用ns1是因?yàn)閚s是namespace的縮寫(xiě),,含義請(qǐng)楚),,在花括號(hào)內(nèi)是聲明塊,,在其中聲明的實(shí)體稱(chēng)為命名空間成員(namespace member)?,F(xiàn)在命名空間成員包括變量a和b,,注意a和b仍然是全局變量,僅僅是把它們隱藏在指定的命名空間中而已,。如果在程序中要使用變量a和b,,必須加上命名空間名和作用域分辨符“::”,如nsl::a,,nsl::b。這種用法稱(chēng)為命名空間限定(qualified),,這些名字(如nsl::a)稱(chēng)為被限定名(qualified name),。c++中命名空間的作用類(lèi)似于操作系統(tǒng)中的目錄和文件的關(guān)系,由于文件很多,,不便管理,而且容易重名,,于是人們?cè)O(shè)立若干子目錄,把文件分別放到不同的子目錄中,,不同子目錄中的文件可以同名,。調(diào)用文件時(shí)應(yīng)指出文件路徑,。
命名空間的作用:是建立一些互相分隔的作用域,,把一些全局實(shí)體分隔開(kāi)來(lái),。以免產(chǎn)生老點(diǎn)名叫李相國(guó)時(shí),,3個(gè)人都站起來(lái)應(yīng)答,,這就是名字沖突,,因?yàn)樗麄儫o(wú)法辨別老師想叫的是哪一個(gè)李相國(guó),,同名者無(wú)法互相區(qū)分,。為了避免同名混淆,學(xué)校把3個(gè)同名的學(xué)生分在3個(gè)班,。這樣,,在小班點(diǎn)名叫李相國(guó)時(shí),,只會(huì)有一個(gè)人應(yīng)答,。也就是說(shuō),在該班的范圍(即班作用域)內(nèi)名字是惟一的,。如果在全校集合時(shí)校長(zhǎng)點(diǎn)名,需要在全校范圍內(nèi)找這個(gè)學(xué)生,,就需要考慮作用域問(wèn)題。如果校長(zhǎng)叫李相國(guó),,全校學(xué)生中又會(huì)有3人一齊喊“到”,,因?yàn)樵谕蛔饔糜蛑写嬖?個(gè)同名學(xué)生。為了在全校范圍內(nèi)區(qū)分這3名學(xué)生,,校長(zhǎng)必須在名字前加上班號(hào),,如高三甲班的李相國(guó),,或高三乙班的李相國(guó),即加上班名限定,。這樣就不致產(chǎn)生混淆。
可以根據(jù)需要設(shè)置許多個(gè)命名空間,,每個(gè)命名空間名代表一個(gè)不同的命名空間域,,不同的命名空間不能同名。這樣,,可以把不同的庫(kù)中的實(shí)體放到不同的命名空間中,或者說(shuō),,用不同的命名空間把不同的實(shí)體隱蔽起來(lái),。過(guò)去我們用的全局變量可以理解為全局命名空間,獨(dú)立于所有有名的命名空間之外,,它是不需要用namespace聲明的,實(shí)際上是由系統(tǒng)隱式聲明的,,存在于每個(gè)程序之中,。
在聲明一個(gè)命名空間時(shí),花括號(hào)內(nèi)不僅可以包括變量,,而且還可以包括以下類(lèi)型: ·變量(可以帶有初始化),; ·常量;
·數(shù)(可以是定義或聲明),; ·結(jié)構(gòu)體; ·類(lèi),; ·模板;
·命名空間(在一個(gè)命名空間中又定義一個(gè)命名空間,,即嵌套的命名空間)。例如
namespace nsl { const int rate=0.08,; //常量 doublepay;
//變量
doubletax()
//函數(shù)
{return a*rate,;} namespacens2
//嵌套的命名空間
{int age,;} }
如果想輸出命名空間nsl中成員的數(shù)據(jù),可以采用下面的方法: cout<
cout<
可以看到命名空間的聲明方法和使用方法與類(lèi)差不多,。但它們之間有一點(diǎn)差別:在聲明類(lèi)時(shí)在右花括號(hào)的后面有一分號(hào),而在定義命名空間時(shí),,花括號(hào)的后面沒(méi)有分號(hào),。
三,、使用命名空間解決名字沖突(使用指南)有了以上的基礎(chǔ)后,,就可以利用命名空間來(lái)解決名字沖突問(wèn)題。現(xiàn)在,,對(duì)例4程序進(jìn)行修改,使之能正確運(yùn)行,。
例5 利用命名空間來(lái)解決例4程序名字沖突問(wèn)題。
修改兩個(gè)頭文件,,把在頭文件中聲明的類(lèi)分別放在兩個(gè)不同的命名空間中,。//例8.5中的頭文件1,,文件名為header1.h using namespace std;#include
#include
namespace ns1 //聲明命名空間ns1 { class student //在命名空間nsl內(nèi)聲明student類(lèi)
{ public: student(int n,string nam,int a){ num=n;name=nam;age=a;} void get_data();private: int num;string name;int age;};void student::get_data()//定義成員函數(shù){ cout<
double fun(double a,double b)//在命名空間n引內(nèi)定義fun函數(shù) { return sqrt(a+b);} } //例8.5中的頭文件2,,文件名為header2.h #include
#include
namespace ns2 //聲明命名空間ns2 { class student { public: student(int n,string nam,char s){ num=n;name=nam;sex=s;} void get_data();private: int num;string name;char sex;};
void student::get_data(){ cout<double fun(double a,double b){ return sqrt(a-b);} } //main file #include
#include ”header1.h“ //包含頭文件l #include ”header2.h“ //包含頭文件2 int main(){ ns1::student stud1(101,”wang“,18);//用命名空間nsl中聲明的student類(lèi)定義studt _data();//不要寫(xiě)成ns1::_data(),;
cout<ns2::student stud2(102,”li“,'f');//用命名空間ns2中聲明的student類(lèi)定義stud2 _data();cout<
分析例4程序出錯(cuò)的原因是:在兩個(gè)頭文件中有相同的類(lèi)名student和相同的函數(shù)名fun,,在把它們包含在主文件中時(shí),就產(chǎn)生名字沖突,,存在重復(fù)定義。編譯系統(tǒng)無(wú)法辨別用哪一個(gè)頭文件中的student來(lái)定義對(duì)象studl?,F(xiàn)在兩個(gè)student和fun分別放在不同的命名空間中,,各自有其作用域,互不相干,。由于作用域不相同,不會(huì)產(chǎn):生名字沖突,。正如同在兩個(gè)不同的類(lèi)中可以有同名的變量和函數(shù)而不會(huì)產(chǎn)生沖突一樣,。
在定義對(duì)象時(shí)用ns1::student(命名空間nsl中的student)來(lái)定義studl,用ns2::student(命名空間ns2中的student)來(lái)定義stud2,。顯然,nsl::student和ns2::student是兩個(gè)不同的類(lèi),,不會(huì)產(chǎn)生混淆。同樣,,在調(diào)用fun函數(shù)時(shí)也需要用命名空間名ns]或ns2加以限定,。ns1::fun()和ns2::fun()是兩個(gè)不同的函數(shù),。注意:對(duì)象studl是用nsl::student定義的,但對(duì)象studl并不在命名空間nsl中,。studl的作用域?yàn)閙ain函數(shù)范圍內(nèi)。在調(diào)用對(duì)象studl的成員函數(shù)get_data時(shí),,應(yīng)寫(xiě)成studl.get_data(),,而不應(yīng)寫(xiě)成nsl::_data(),。程序能順利通過(guò)編譯,并得到以下運(yùn)行結(jié)果: 101 wang l9(對(duì)象studl中的數(shù)據(jù))2.82843(/5+3的值)102 li f(對(duì)象studg中的數(shù)據(jù))1.41421(/5-2的值)
四,、使用命名空間成員的方法 從上面的介紹可以知道,在引用命名空間成員時(shí),,要用命名空間名和作用域分辨符對(duì)命名空間成員進(jìn)行限定,以區(qū)別不同的命名空間中的同名標(biāo)識(shí)符,。即: 命名空間名::命名空間成員名
這種方法是有效的,,能保證所引用的實(shí)體有惟一的名字。但是如果命名空間名字比較長(zhǎng),,尤其在有命名空間嵌套的情況下,為引用一個(gè)實(shí)體,,需要寫(xiě)很長(zhǎng)的名字,。在一個(gè)程序中可能要多次引用命名空間成員,,就會(huì)感到很不方便,。1、使用命名空間別名
可以為命名空間起一個(gè)別名(namespace alias),,用來(lái)代替較長(zhǎng)的命名空間名。如 namespace television //聲明命名空間,,名為television {...} 可以用一個(gè)較短而易記的別名代替它。如:
namespace tv=television,; //別名tv與原名television等價(jià)
也可以說(shuō),別名tv指向原名television,,在原來(lái)出現(xiàn)television的位置都可以無(wú)條件地用tv來(lái)代替。
2,、使用using命名空間成員名
using后面的命名空間成員名必須是由命名空間限定的名字。例如: using nsl::student,; 以上語(yǔ)句聲明:在本作用域(using語(yǔ)句所在的作用域)中會(huì)用到命名空間ns1中的成員student,在本作用域中如果使用該命名空間成員時(shí),,不必再用命名空間限定。例如在用上面的using聲明后,,在其后程序中出現(xiàn)的student就是隱含地指nsl::student,。
using聲明的有效范圍是從using語(yǔ)句開(kāi)始到using所在的作用域結(jié)束。如果在以上的using語(yǔ)句之后有以下語(yǔ)句:
student studl(101,”wang“,18),; //此處的student相當(dāng)于ns1::student 上面的語(yǔ)句相當(dāng)于
nsl::student studl(101,”wang“,,18),; 又如
using nsl::fun,; //聲明其后出現(xiàn)的fun是屬于命名空間nsl中的fun cout<
但是要注意:在同一作用域中用using聲明的不同命名空間的成員中不能有同名的成員,。例如:
usmgnsl::student; //聲明其后出現(xiàn)的student是命名空間nsl中的student usmgns2::student,; //聲明其后出現(xiàn)的student是命名空間ns2小的student student stud1,; //請(qǐng)問(wèn)此處的student是哪個(gè)命名中間中的student? 產(chǎn)生了二義性,,編譯出錯(cuò),。
3、使用using namespace命名空間名
用上面介紹的using命名空間成員名,,一次只能聲明一個(gè)命名空間成員,如果在一個(gè)命名空間中定義了10個(gè)實(shí)體,,就需要使用10次using命名空間成員名。能否在程序中用一個(gè)語(yǔ)句就能一次聲明一個(gè)命名空間中的全部成員呢? c++提供了using namespace語(yǔ)句來(lái)實(shí)現(xiàn)這一目的,。using namespace語(yǔ)句的一般格式為 using namespace 命名空間名,; 例如
using nanlespace nsl,;
聲明了在本作用域中要用到命名空間nsl中的成員,在使用該命名空間的任何成員時(shí)都不必用命名空間限定,。如果在作了上面的聲明后有以下語(yǔ)句: student studl(101,”wang”,,18); //student隱含指命名中間nsl中的student cout<
cout<
student stud2(102,,“l(fā)i”,'r'),; _data();
coutt<
五,、無(wú)名的命名空間
以上介紹的是有名字的命名空間,c++還允許使用沒(méi)有名字的命名空間,,如在文件a中聲明了以下的無(wú)名命名空間:
namespace //命名空間沒(méi)有名字 { void fun()//定義命名空間成員 { cout<<“ok.”<
則執(zhí)行無(wú)名命名空間中的成員fun函數(shù),,輸出”ok.”,。
在本程序中的其他文件中也無(wú)法使用該fun函數(shù),也就是把fun函數(shù)的作用域限制在本文件范圍中,。可以聯(lián)想到:在c浯言中可以用static聲明一個(gè)函數(shù),,其作用也是使該函數(shù)的作用域限于本文件,。c++保留了用static聲明函數(shù)的用法,,同時(shí)提供了用無(wú)名命名空間來(lái)實(shí)現(xiàn)這一功能。隨著越來(lái)越多的c++編譯系統(tǒng)實(shí)現(xiàn)了ansi c++建議的命名空間的機(jī)制,,相信使用無(wú)名命名空間成員的方法將會(huì)取代以前習(xí)慣用的對(duì)全局變量的靜態(tài)聲明。
六,、標(biāo)準(zhǔn)命名空間std 為了解決c++標(biāo)準(zhǔn)庫(kù)中的標(biāo)識(shí)符與程序中的全局標(biāo)識(shí)符之間以及不同庫(kù)中的標(biāo)識(shí)符之間的同名沖突,應(yīng)該將不同庫(kù)的標(biāo)識(shí)符在不同的命名空間中定義(或聲明),。標(biāo)準(zhǔn)c++庫(kù)的所有的標(biāo)識(shí)符都是在一個(gè)名為std的命名空間中定義的,,或者說(shuō)標(biāo)準(zhǔn)頭文件(如iostream)中函數(shù),、類(lèi)、對(duì)象和類(lèi)模板是在命名空間std中定義的,。std是standard(標(biāo)準(zhǔn))的縮寫(xiě),表示這是存放標(biāo)準(zhǔn)庫(kù)的有關(guān)內(nèi)容的命名空間,,含義請(qǐng)楚,,不必死記,。
這樣,,在程序中用到c++標(biāo)準(zhǔn)庫(kù)時(shí),,需要使用std作為限定,。如
std::cout<<“ok.”<
這樣,在std中定義和聲明的所有標(biāo)識(shí)符在本文件中都可以作為全局量來(lái)使用,。但是應(yīng)當(dāng)絕對(duì)保證在程序中不出現(xiàn)與命名空間std的成員同名的標(biāo)識(shí)符,例如在程序中不能再定義一個(gè)名為cout的對(duì)象,。由于在命名空間std中定義的實(shí)體實(shí)在太多,有時(shí)程序設(shè)計(jì)人員也弄不請(qǐng)哪些標(biāo)識(shí)符已在命名空間std中定義過(guò),,為減少出錯(cuò)機(jī)會(huì),,有的專(zhuān)業(yè)人員喜歡用若干個(gè)"using命名空間成員”聲明來(lái)代替“using namespace命名空間”聲明,,如 using std::string,; using std::cout; using std::cin,;
等。為了減少在每一個(gè)程序中都要重復(fù)書(shū)寫(xiě)以亡的using聲明,,程序開(kāi)發(fā)者往往把編寫(xiě)應(yīng)用程序時(shí)經(jīng)常會(huì)用到的命名空間std成員的usmg聲明組成一個(gè)頭文件,然后在程序中包含此頭文件即可,。
如果閱讀了多種介紹c++的書(shū),可能會(huì)發(fā)現(xiàn)有的書(shū)的程序中有using namespace語(yǔ)句,,有的則沒(méi)有。有的讀者會(huì)提出:究竟應(yīng)該有還是應(yīng)該沒(méi)有?應(yīng)當(dāng)說(shuō):用標(biāo)準(zhǔn)的c++編程,,是應(yīng)該對(duì)命名空間std的成員進(jìn)行聲明或限定的(可以采取前面介紹過(guò)的任一種方法),。但是目前所用的c++庫(kù)大多是幾年前開(kāi)發(fā)的,,當(dāng)時(shí)并沒(méi)有命名空間,庫(kù)中的有關(guān)內(nèi)容也沒(méi)有放在std命名空間中,因而在程序中不必對(duì)std進(jìn)行聲明,。
七、使用早期的函數(shù)庫(kù)
c語(yǔ)言程序中各種功能基本上都是由函數(shù)來(lái)實(shí)現(xiàn)的,,在c語(yǔ)言的發(fā)展過(guò)程中建立了功能豐富的函數(shù)庫(kù),c++從c語(yǔ)言繼承了這份寶貴的財(cái)富,。在c++程序中可以使用c語(yǔ)言的函數(shù)庫(kù)。如果要用函數(shù)庫(kù)中的函數(shù),,就必須在程序文件中包含有關(guān)的頭文件,在不同的頭文件中,,包含了不同的函數(shù)的聲明,。
在c++中使用這些頭文件有兩種方法,。
1、用c語(yǔ)言的傳統(tǒng)方法
頭文件名包括后綴.h,,如stdio.h,math.h等,。由于c語(yǔ)言沒(méi)有命名空間,,頭文件并不存放在命名空間中,因此在c++程序文件中如果用到帶后綴.h的頭文件時(shí),,不必用命名空間。只需在文件中包含所用的頭文件即可,。如 #include
2、用c++的新方法c++標(biāo)準(zhǔn)要求系統(tǒng)提供的頭文件不包括后綴.h,,例如iostream、string,。為了表示與c語(yǔ)言的頭文件有聯(lián)系又有區(qū)別,,c++所用的頭文件名是在c語(yǔ)言的相應(yīng)的頭文件名(但不包括后綴.h)之前加一字母c,。例如,c語(yǔ)言中有關(guān)輸入與輸出的頭文件名為stdio.h在c++中相應(yīng)的頭文件名為cstdio,。c語(yǔ)言中的頭文件math.h,在c++中相應(yīng)的頭文什名為cmath,。c語(yǔ)言中的頭文件string.h在c++中相應(yīng)的頭文件名為cstring,。注意在c++中,頭文件cstnng和頭文件strmg不是同一個(gè)文件,。前者提供c語(yǔ)言中對(duì)字符串處理的有關(guān)函數(shù)(如strcmp,,ctrcpy)的聲明,,后者提供c++中對(duì)字符串處理的新功能,。此外,由于這些函數(shù)都是在命名空間std中聲明的,,因此在程序中要對(duì)命名空間std作聲明。如:
#include
#include
using namespace std,;
目前所用的大多數(shù)c++編譯系統(tǒng)既保留了c的用法,又提供丁c++的新方法,。下面兩種用法等價(jià),可以任選,。c傳統(tǒng)方法 c++新方法#include
#include
#include
#include
#include
#include
using namespace std,;