天天看點

C++------函數重載,預設參數,命名空間

C++介紹

C語言是一種結構化的程式設計語言。

最初是為了開發UNIX作業系統,由丹尼斯裡奇和肯湯姆遜在B語言的基礎上于貝爾實驗室開發出來的。C語言是一種面向過程的語言,适合處理較小規模的程式。對于複雜的,大規模的程式,需要高度的抽象,此時C語言就不再适合。是以,在C語言的基礎上又增加了新的特性————類,最初,稱其為“帶類的C語言”。後來,又再次基礎上增添了更多的新特性。是以,将其重新命名為“C++”。C++是相容C語言的,是以C語言可以說是C++的一個子集。

C++是一種基于面向對象的程式設計語言(不是純面向對象的語言,因為它相容C語言)。

面向對象的三大特性:封裝,繼承,多态。

其中封裝主要展現在兩方面:

1. 将程式和資料封裝在類中。其中對象是類的執行個體,類是對對象共有屬性的抽象。以對象作為程式的基本單元,以提高程式的複用性,靈活性和擴充性。

2. C++中設定通路限定符,可以實作程式代碼塊内部的高内聚,代碼塊之間的高耦合。C++中的限定符有三種:public(公有),private(私有),protected(受保護的)。其中:

(1)public成員在類内類外可以直接通路。private成員在類内可以直接通路,但不能在類外直接通路。protected成員可以在類内部和子類的内部直接通路;

(2)在一個類内部,限定符可以使用多次,限定符的作用域為從定義處到下一個限定符定義處或類結束處;

(3)如果類中沒有定義限定符,則類成員預設為私有的。在C++中,struct除了用于聲明結構體外,還可以聲明類,與class不同的是,struct聲明的類如果沒有通路限定符,則類成員預設為公有的;

C++中的資料類型:

除了包含C語言中的基本資料類型和自定義資料類型外,還新增了bool類型,class(類)類型。

C++的作用域:

除了包含C語言中的局部域和全局域外,還包含命名空間域和類域。

C++支援函數重載

函數重載:是指在同一作用域内,一組函數的函數名相同,函數的參數類型或者參數個數不同,函數傳回值任意(可相同可不同)
C++中支援函數重載,C語言中不支援函數重載。
           

C語言不支援重載:

reload.c
#include<stdio.h>                                                                                                                                                 
int fun(int a,int b)
{
    return a + b;
}
int fun(double a,int b)
{
    return b;
}
int main()
{
    fun(,);
    fun(,);
    return ;
}
           

對上述代碼進行編譯:

C++------函數重載,預設參數,命名空間

由上述結果可以看出C語言中不支援函數重載。

C++支援重載:

reload.cpp
#include<iostream>
using namespace std;
int fun(int a,int b)
{
    return a + b;
}
//函數的重載
int fun(double a,int b)
{
    return b;
}
int main()
{
    cout<<fun(,)<<endl;
    cout<<fun(,)<<endl;
    return ;
}
           

編譯運作上述程式:

C++------函數重載,預設參數,命名空間

通過上述結果可以知道C++支援函數重載。

為什麼C++支援重載,C語言不支援重載?
           

在LInux下對上述兩個程式生成目标檔案(.o檔案),通過以下指令檢視彙編代碼:

C語言:objdump -D reloadc.o
C++:objdump -D reloadcpp.o
           
C++------函數重載,預設參數,命名空間
C++------函數重載,預設參數,命名空間

通過上述的結果對比,可以看出C語言中通過函數名對函數進行辨別,而在C++中不僅通過函數名還有函數參數的個數和類型來對函數進行辨別。當C語言中兩函數的函數名相同時,即使參數不同也會被認為是重定義。但是,C++中函數名相同,隻要參數不同就可以進行區分。

是以說,C++支援函數重載的原因是符号表中存放的函數名+函數個數+函數類型。C語言不支援函數重載的原因是符号表中存放的隻有函數名。

C++中函數的預設參數

預設參數:在函數的形參清單中對參數賦予預設值的參數。

函數的參數可以分為:

全預設參數:形參全部設定預設值

半預設參數:對部分形參設定預設值

無預設參數:所有形參都不設定預設值

下面通過代碼來說明:

#include<iostream>
using namespace std;
//無預設
int fun(int a,int b)
{
    return a + b;
}
//半預設
int fun(int a,int b = )
{
    return a + b;
}
**//半預設,隻能從右往左預設,該情形錯誤
int fun(int a = ,int b)
{
    return a + b;
}**
//全預設
int fun(int a = ,int b = )
{
    return a + b;
}
//函數的重載                                                                                                                                        
//函數的重載與預設參數的重載函數沖突時,會報錯
int fun(int a)
{
    return a;
}

int main()
{
    //對于預設的函數來說,如果有傳實參,則使用實參,否則用預設的行參
    //調用全預設或半預設,當兩者共存時,會發生錯誤
    //調用全預設時:a = 1,b = 2
    //調用半預設時:a = 1,b = 5
    cout<<fun(,)<<endl;
    //調用半預設參數或隻有一個int類型參數的重載函數,當二者并存時,會發生沖突
    cout<<fun()<<endl;
    return ;
}     
           

注意:

(1)預設參數隻能從右往左連續設定

(2)對于預設參數,若傳遞了實參,則用實參;若沒有傳遞,則使用預設參數

(3)當某些全預設參數函數和半預設參數函數以及函數重載發生沖突時,會報錯。

(4)預設參數不能在聲明和定義中同時出現。在聲明中出現了預設參數,定義中就不能出現;在聲明中沒有出現預設參數,則定義中可以出現(也可以不出現)。函數的使用按照聲明的格式來調用。

(5)預設參數的值可以使用宏和全局變量。

命字空間

命字空間域相當于一個檔案域。它是用來解決全局命名沖突的問題的。
           

命字空間的定義:以關鍵字namespace開頭聲明一個命字空間,“{}”内表示命字空間中的内容。

std:存放标準C++庫中的所有元件的命字空間

如:

namespace name1
{
    int a = ;
}
namespace name2
{   
    int a = ;
}
           

命字空間的使用方法:

(1)using namespace 名字空間名;(指定該名字空間為全局域)

(2)名字空間名::名字空間中的内容(“::”表示域作用解析符,用于指明使用哪個域)

如:

using namespace std; 表示程式中某些變量預設使用名字空間std中定義的變量。

name1::a:此時的a的值即為10,而不是20。

變量的通路規則:

1. 如果通路的變量沒有指定名字空間域。

(1)如果在main中被定義為了局部變量,則遵循就近原則,通路該局部變量。

.......
int a = ;
int main()
{
    int a = ;
    cout<<a<<endl;//輸出10
}
           

(2)如果沒有,則通路定義的全局變量。如果定義了全局變量或者using指定的全局域中都有定義該變量,則發生沖突。

namespace name1
{
    int a = ;
}
int a = ;
using namespace name1;
int main()
{
    //此時會通路沖突,因為定義了全局變量a =20
    //又指定了全局域name1,name1中也有變量a
    cout<<a<<endl;
}
           

2 如果通路的變量指定了名字空間域

(1)如果顯式指定了名字空間域,則根據指定的名字空間域進行查找,找不到則報錯;如:

namespace name1
{
    int a = ;
}
int a = ;
int main()
{
    int a = 
    //此時會通路name1中的變量a,是以a為10;
    //如果沒有定義名字空間name1或者name1中沒有定義變量a,則出錯
    cout<<name1::a<<endl;
}
           

(2)如果通路的變量形式”::a”,此時表示的是在全局域中通路a;對于a的通路遵循以下規則:

i)如果有全局變量,則通路全局變量a;

ii)如果沒有全局變量a,則在全局域(using指定的全局域)中通路a,如果沒有全局域或者全局域中沒有變量a,則出錯;如果using指定了多個全局域,若多個全局域中有多個a,則沖突出錯;如果多個全局域中隻有一個定義了a,則通路a;如:

.......
namespace name1
{
    int a = ;
}
namespace name2 
{
    int a = ;
}
using namespace name1;
using namespace name2;
int a = ;
int main()
{
    cout<<::a<<endl;//此時通路全局變量a=30
}
           
.......
namespace name1
{
    int a = ;
}
namespace name2 
{
    int a = ;
}
using namespace name1;
using namespace name2;
int main()
{
    //此時通路沖突
    cout<<::a<<endl;
    //若全局域隻指定了name1或者隻指定了name2,則通路相應的全局域
}
           

注意:

1. using可以指定多個名字空間,隻要通路的變量不在多個名字空間中存在即可;

2.命字空間可以嵌套定義,通路時也要嵌套通路。

繼續閱讀